Hurlman.Tech

/* Blogging when the NDA allows */

I've had a recent need to use jQuery for the first time, and at first blush, it's really a rather well done library.  In fact, I'd wager that the problems I'd recently run into had very little, if nothing to do with the core jQuery code.  I think the fault may lie with simpleModal, but the ever popular juxtaposition of coding with something completely new and being under a tight deadline this week is causing me to forgo troubleshooting the code I was told I had to use for now.

Problem: After loading up a hidden DIV with content, showing it as a dialog via $.ajax(...) and modal(...) calls, and closing the dialog using the built-in simpleModal functionality, subsequent attempts to cause an ASP.Net postback on the page failed miserably with a JavaScript error: "theForm.__EVENTTARGET is null or not an object". Popping other dialog boxen worked just fine.

Just the facts:

  1. The content rendered into the dialog box is the result of a same-page GET, which results in a single User Control being rendered to the Response.OutputStream.
  2. RenderControl on the user control was failing unless the content of the control was rooted in a server-side form element.
  3. When the dialog was rendered, the control's form element was rendered as well, with the same id and name as the page's form element.
  4. When the dialog was closed, the default simpleModal functionality left behind the control's form element, albeit empty.
  5. Despite all this, postbacks worked just fine in Firefox (naturally)

The solution (as of my last checkin before lunch):

  1. Override the dialog's onClose event, and do the following:
    1. Call the dialog's default Close function
    2. Set the dialog div's innerHTML to a single  
    3. Hijack __doPostBack, pointing it to a new function, newDoPostBack

From some comments I’ve seen on the web, point 1 needs some clarification.  Unfortunately, I’m no longer with the same employer, and don’t have access to the code I used, but I’ll do what I can.  First off, you need to override the dialog’s onClose function by defining a new function, and pointing your dialog to it, like this:

$('#myJQselector).modal({onClose: mynewClose});
  • Call the dialog's default Close function.  In the function you define, you should first call the default functionality (a best practice for just about anything you override usually):
  • Set the dialog div's innerHTML to a single   – This is not a required step, so skip it if you don’t understand this.
  • Hijack __doPostBack, pointing it to a new function, newDoPostBack
function myNewClose (dialog)
{
    dialog.close();
    __doPostBack = newDoPostBack;
}
  1. Write the newDoPostBack function:
function newDoPostBack(eventTarget, eventArgument)
{
    var theForm = document.forms[0];
    if (!theForm)
    {
        theForm = document.aspnetForm;
    }
 
    if (!theForm.onsubmit || (theForm.onsubmit() != false))
    {
        document.getElementById("__EVENTTARGET").value = eventTarget;
        document.getElementById("__EVENTARGUMENT").value = eventArgument;
        theForm.submit();
    }
}
	

The newDoPostBack function differs from the original __doPostBack in three small but significant ways.  First, it finds the theForm variable every time it's called; something in the dialog's lifecycle was causing the original page-level JavaScript variable to get nulled-out.  Second, it finds that variable using an integer indexer, and not via the string indexer, by name.  For some reason, getting it by name returned a JS variable of type DispHTMLElementCollection, and not DispHTMLFormElement.  You can't call submit() on the former, so we use the integer indexer to get the latter.  Third, getting the __EVENT* fields using the DOM (i.e. document.__EVENTTARGET) was not working - something about the dialog lifecycle broke this as well.  However, using document.getElementById still gets us what we want, so we use that.

Once we do all that, we get our post-dialog postbacks back.  Thank God for the new-and-improved IE Developer Toolbar with built-in DOM inspector; it was a piece of memorry-hogging CRAP back in 2006, but seems to be behaving itself now.

- G 


There must be a way to change this.  Finally on my way to developing my first full-fledged .Net 2.0 app as a side project, and I notice that the code-behind page that Visual Studio 2005 gives you is missing a few things, most notably the control definitions and Page_Init.  Well, problem easily solved... right-click the class name for the page, click "Find All References", and lo and behold, I get a list - one of which looks like this:

public partial class signup : System.Web.SessionState.IRequiresSessionState {
Well, that looks like what I'm looking for, so I double-clicked the result... and got this:



Are they serious?  That's the default for this sort of thing?  Hmmm... can't be just me looking for this, so I searched Google Groups... nothing.  Searched the web... one thing in Russian I think... not much help.  So (*groan*) I dove into the options... to no avail.

This is just silly.  I found this blog entry that discusses how ASP.Net 2.0 automagically wires up Page_* methods to events if AutoEventWireup is set to true in the @Page directive - automagic is fine, but there really should be a way you can take a look at and even control the code that gets generated.  Maybe it's just the talk by Charles Petzold that I attended last year, but not having control over something like variable declarations and event hookup, even if I wouldn't change it 99% of the time is just troubling.  If I've learned anything being a Microsoft developer, it's that if there's one circumstance that will cause their automagic, drag-and-drop demos to be not so magical - that circumstance will come up time and time and time again (see also: anything but a TemplateColumn on a DataGrid).

I know I'm late to the party - but I hadn't expected to hit this sort of thing the very first day I decided to wire up a control's events... lame.

[Update: I've opened a bug on the MSDN feedback site for this - give it a vote if you have a spare second or 3.]
Creative Commons License This work is licensed under a Creative Commons License.

From Minh Nguyen via DotNetJunkies:

One of the most overlooked features of ASP.NET 2.0, part of Visual Studio 2005 or "Whidbey", is the Client Callback feature. This feature allows you to programmatically call server-side methods through client-side JavaScript code without the need for posting back the page. This article describes how to use the Client Callback feature to implement your own callback scenario and introduces the new TreeView control that has this feature built in.

Minh's well written article leads you through how the ASP.Net 2.0 Treeview control utilizes the new client callback system, and shows you how to develop pages, user controls, or custom controls that use this system as well.  I haven't seen much other useful information on this very promising functionality - make a point of giving this article a read.

- G



Creative Commons License This work is licensed under a Creative Commons License.

I got my PDC DVDs in the mail recently, and as such, I have gotten back into the swing of playing with the new features of ASP.Net.  The problem is, there are a few issues.  Of course there are, and I'm not upset about it... it's expected.  However, I'm starting to slowly go mad, as I just don't know which problems are bugs in the framework, and which problems are bugs in my code.

The most maddening one right now involves the treeview control, which I'm certain must work somewhat, as I've seen a number of people talking about how to modify the default behavior.  Me?  I'd be totally content with the default behavior.

Here's the situation:  I've got a master page, and on that master page I have both a TreeView and a SiteMapPath control.  I've also got a SiteMapDataSource, pointing to the app.sitemap file in the root of my application.  Simple drag & drops, nothing spectacular - that'll come once it all works (hopefully before 2005).  The problem is, I get a JavaScript error every time I try to expand or collapse a branch of the tree.

The error I get is: '_ctl0$tvLeftNav_Data' is undefined

My ASPX source looks like this:

<asp:treeview id=tvLeftNav datasourceid="smdMain" runat="server"
    initialexpanddepth="1" />
<asp:sitemapdatasource id=smdMain runat="server"
    sitemapviewtype="Tree" />

The resulting related hidden input fields look like this:

<INPUT type=hidden name=_ctl0$tvLeftNav_ExpandState value=ecnnnncnn>
<INPUT type=hidden name=_ctl0$tvLeftNav_SelectedNode>
<INPUT type=hidden name=_ctl0$tvLeftNav_PopulateLog>

Sure enough, the _Data field is missing.  So, am I doing something wrong, or is this just the way it is?  Any insight anyone can give would be great... I'm hoping to get past this before frustration gets the best of me, making me wait for Beta 1 before trying again.

- G



Creative Commons License This work is licensed under a Creative Commons License.