Update ASP.net DataGrid Textbox Value from Popup Window
I am using an old school ASP.net DataGrid with inline editing. When I click on a row’s edit link the row values turn into HTML textboxes and other controls for inline editing. The Id of the controls are scoped by the Id of parent container (e.g. the DataGrid), your normal ASP.net unique naming convention. I need to attach a JavaScript event handler function to a textbox’s onclick event. This function will open an image file browser in a new window (popup). The image file browser let’s me upload select an image from an image library. Once selected, I click a button and it triggers a function to pass data to the caller (generally passing the image URL to a textbox/WYSIWYG editor). The basic mechanics of the button’s onclick handler is to call a function that uses window.opener to send the data back to the original window. My mission today is cross window communication where I have the image file browser’s button onlick handler pass the selected image URL to the textbox that was clicked in the DataGrid. Additionally, I have to shorten the URL to a virtual URL because the image file browser sends an absolute URL.
First thing first, how do we attach an event handler to a dynamically created textbox that is added to the DOM after everything is hooked up. Let’s ask Google. [Time Lapse…about 5 minutes in the future] OK, I’m back and I found a nice answer that references the all powerful jQuery library, which I’m already using so this was great. The jQuery ‘live’ function can attach events to DOM elements that are added after the page is all loaded. I knew this, used it a few times before, but it just didn’t occur to me to use it, duh (these brain farts are common in caffeine induced states).
$(<selector>).live("click", function() {
// cool code here
});
Google Search: “attach javascript event to dynamic element”
Answer URL: http://stackoverflow.com/questions/1359018/in-jquery-how-to-attach-events-to-dynamic-html-elements
OK, that is working nicely, thank God for Google. Note to self: jQuery live can attach a function to dynamically created controls (write it 50 times on the blackboard).
Now I have to open my image file browser. We add a CssClass attribute (class name ‘visual’) to the ItemStyle of the column we want to use to open the image file browser. We will use a simple window.open function for this (actually I will use a popup and center function that I get a lot of reuse out of).
$(function () {
$(".visual").live("click", function () {
PopUp('imagegallery.aspx?no-ck=1&type=file', 'gallery', 300, 400, 1);
});
});
Thinking ahead I don’t readily see how to return the image URL to a dynamically created textbox. Normally, I would use window.opener and statically target a known element. Put another way, I usually know what element to target and I can write code that speaks to it directly (hardcode the control Id). In this instance, my element is dynamically generated, so I don’t know who to talk to. Another problem is my image browser uses some heavy JavaScript, but no jQuery so I’m not sure if it will play nice with jQuery. Well, it can’t hurt to try and find out, but I think I can get my textbox selected in the parent (opener) where I can use jQuery no problem. We will experiment with breaking the image file browser later.
Let’s add a selector that will find the textbox. Wait, how do I select it? This is what a text box Id looks like, ctl00$MainBody$dg$ctl02$ctl07 (classic ASP.net WTF). If I edit the row below it I get this, ctl00$MainBody$dg$ctl03$ctl07 for the text box Id. So, I have the DataGrid Id, ctl00$MainBody$dg, and the row/column, $ctl02$ctl07. The variable is the row. Alrighty then, we can do this. Let’s build a jQuery selector that can find this row column. Dang, I am embarrassed to say that I don’t know how to do this off the top of my head. No problem that a quick search of the jQuery docs can’t fix. Since there will only be one row selected at a time, hence one control at $ctl<number>$ctll07, we will take a chance with an Attribute Ends With Selector and target the column, $ctl07.
$([id$=$ctl07])
Yes, I hear all the problems you are rattling off. I know if something changes in the container or DataGrid naming, if I change the column order, or whatever else, that it will mess this up, but I’m betting that it won’t happen anytime soon. In the real world, when something is stable, and this DataGrid’s page has been for years, it’s safe to cut corners. Plus, if it does change it is an easy fix and we can harden the implementation when and if the situation calls for it. So, let’s add this to a function that our image file browser window.opener function can call and see if we get our URL back. My code in the image file browser is:
window.opener.UpdateUrl(fileUrl);
And on the DataGrid page
function UpdateUrl(url) {
$("[id$='$ctl07']").val(url);
}
After some soul searching, calming exercises and clever Firebug JavaScript debugging, I discovered that my sleepy eyes where reading “name” and interpreting “id”. So, here is the updated JavaScript with the attribute updated to the actual, not imaginary, value. (Note: I moved selector result to a variable to aide debugging)
function UpdateUrl(url) {
var textBox = $("input[name$='ctl07']");
textBox.val(url);
}
Yeah! That worked. We can open the image file browser by clicking a text box in the DataGrid and the image browser is passing the URL back to the text box.
Now we have to get the virtual path, with no leading slash. I want to get the part of the path that does not include the domain name (e.g. from http://www.mydomain.com/mydirectory/myfile.htm to read only mydirectory/myfile.htm) Since we need speed, this has taken too long, no need in reinventing the wheel. Let’s try borrowing a function from, http://blog.programmingsolution.net/javascript/url-parsing-using-javascript-get-domain-name-port-number-and-virtual-directory-path/.
function GetVirtualDirectory(url) {
var urlParts = url.split('/');
urlParts[urlParts.length - 1] = '';
var virtualPath = urlParts.join('/');
return virtualPath;
}
I know my mother told me to read code before I use it, this is not what I need. If you didn’t notice, the code snip above chops off the end of the URL, the very part I want. Well, I’m tired and I need to be done with this so I present this ugly ball of goo:
function GetVirtualPath(url) {
var urlParts = url.split('/');
urlParts[0] = '';
urlParts[1] = '';
urlParts[2] = '';
var virtualPath = urlParts.join('/');
virtualPath = virtualPath.substring(3, virtualPath.length);
return virtualPath;
}
Same logic just removing the first 3 indexes from urlParts to remove http://www.mydomain.com. Yes this will be refactored to use replace or something a little more sanitary. I just code the first and simplest thing that came to mind.
Well that’s it for now. I have been getting requests for this for a while and it took me about 2 hours to plan, research, code, debug, test, and blog. From my ASP.net DataGrid I am able to click on a textbox to open a custom image file browser, select an image, and insert the value of the virtual path for the image in a text box in the DataGrid. By the way, this little ditty is for an XML based editor that allows users to add and remove images for a JavaScript image scroller.
View more posts in:
ASP.net
JavaScript
jQuery
UI


Leave a Reply