RegisterStartupScript firing at the wrong time

Discussion in 'ASP .Net Building Controls' started by lisa, Apr 18, 2005.

  1. lisa

    lisa Guest

    I have a weird thing going on. I think I've figured out what's causing
    my problem, but I can't find any way to fix it.

    I have a custom server control that wraps a <select> in a <div> in
    order to emulate a WinForms listbox. It works nicely.

    I have another custom server control that includes two of the custom
    listboxes and some buttons and is a Dual/Double/Swap/Pick list. You've
    all seen the sort of thing I mean. It works nicely also.

    Here's my problem. For the custom ListBox to work, it has to emit
    three lines of startup script, one of which calls a function that
    resizes the <select> within the <div>. That works fine as well.

    My problem comes when I databind the two internal ListBoxes inside of
    my PickList. Databinding them causes <option>s to be added to the
    <select>s. But the startup script fires before the databinding, when
    the <select>s are empty. So it doesn't work properly.

    The thing is, I'm not always going to be databinding. I can add
    records manually as well (PickList.SourceItems.Add(...), for instance).
    I don't want to fire the startup script for each item that gets bound
    into the listbox(es). Just once per listbox, when the page is fully
    loaded into the browser. That shouldn't be a problem, should it?

    But it seems that the ListBoxes emit the javascript as soon as they're
    loaded into the PickList. Before databinding (or adding).

    I don't want to force the users to have to put an onload event onto
    their <body> tags, or add runat=server to the <body> tags either. I'd
    like this to be a simple, usable component.

    Ultimately, if I absolutely have to, I can be object disoriented and
    copy the code for the custom listboxes into the picklist. But OOP
    isn't supposed to be like that.

    Can anyone here make a suggestion as to how I can get the startup
    script to run only after the page is finished loading in the browser?
     
    lisa, Apr 18, 2005
    #1
    1. Advertisements

  2. lisa

    Dale Guest

    When you add a script using RegisterStartupScript, even from within a user
    control, the script is added just before the closing tag of the form element
    - just before the </form> tag.

    At that time, all objects in the page should have been created. That is why
    the startup scripts are placed there, while RegisterClientScriptBlock puts
    the scripts immediately after the opening <form> tag.

    Databinding should have no effect because databinding occurs on the server
    side and the startup script is on the client side.

    If your startup scripts are referencing items not yet rendered to the page
    then check that the <select> is within the first <form></form> block on the
    page (and there should only be one, right?)

    If you still have problems, you can add, in a startup script, something like
    the following:

    function init() {
    // do something here with your <select>
    }
    window.onload = init;

    HTH

    Dale Preston
    MCAD, MCDBA, MCSE
     
    Dale, Apr 19, 2005
    #2
    1. Advertisements

  3. lisa

    lisa Guest

    Yep. And it's definitely within the <form> tags. I thought to maybe
    call the same startup script from the parent control, referencing the
    two children controls. But I wound up with this just before the
    </form> tag:

    <script language='javascript' type='text/javascript' >
    <!--
    alert(1);
    objSelect = document.getElementById('plUsers_SourceListBox');
    objSelect.size = 294;
    objSelect.selectedIndex = -1;
    LLResizeSelect(objSelect);
    LLShowOption(objSelect);
    alert(2);
    objSelect = document.getElementById('plUsers_PickedListBox');
    alert(2.1);
    objSelect.size = 11;
    alert(2.2);
    objSelect.selectedIndex = -1;
    alert(2.3);
    LLResizeSelect(objSelect);
    alert(2.4);
    LLShowOption(objSelect);
    alert(2.5);
    //-->
    alert(2.6);
    </script>

    <script language='javascript' type='text/javascript' >
    alert(2.7);
    <!--
    alert(3);
    objSelect = document.getElementById('plUsers_SourceListBox');
    objSelect.size = 294;
    objSelect.selectedIndex = -1;
    LLResizeSelect(objSelect);
    LLShowOption(objSelect);
    //-->
    </script>

    <script language='javascript' type='text/javascript' >
    <!--
    alert(4);
    objSelect = document.getElementById('plUsers_PickedListBox');
    objSelect.size = 11;
    objSelect.selectedIndex = -1;
    LLResizeSelect(objSelect);
    LLShowOption(objSelect);
    //-->
    </script>

    Which doesn't look like a problem. Except that I get a "Stack Overflow
    at Line 0" between alerts 2.6 and 2.7. It seems that the browser
    doesn't like ending a script block and starting a new one that fast.
    The question is, can I do window.onload = init more than once in a
    page? I can't put all of the startup script stuff for all of the
    custom listboxes on the page into a single function, because .NET won't
    let me combine them that way. So I'd have to do something like this:

    function init_listbox1() {
    // do something here with your <select>
    }
    window.onload = init_listbox1;

    function init_listbox2() {
    // do something here with your <select>
    }
    window.onload = init_listbox2;

    And I suspect that only init_listbox1 will fire in that case. But I'll
    try it and see what happens. Thanks.

    Lisa
     
    lisa, Apr 19, 2005
    #3
  4. lisa

    lisa Guest

    Yeesh. Never mind. I'm just an idiot.

    The problem was that the listboxes were in a MultiPage control, and
    weren't showing at the time the page loaded. As a result, there were
    no values for things like offsetHeight and offsetWidth, and nothing
    happened.

    The Stack Overflow error was because I'd tried putting an
    onpropertychange event on the controls to resize them, and calling that
    rapid fire 291 times in a row was too much for my processor.

    My solution was to put an onresize event on the controls. Because when
    the control first appears in the browser window, the browser sets the
    offsetHeight and offsetWidth values, which counts as resizing. Go
    figure. And because my resize function would have looped me until the
    heat death of the universe, I put in an objSelect.onresize = null line
    at the beginning of the resize routine.

    Thanks for wasting time on my dumb mistake.

    Lisa
     
    lisa, Apr 19, 2005
    #4
  5. lisa

    Dale Guest

    Well, you're clearly not an idiot. You solved the problem. One thing that
    sets you above many others is that you shared the solution with us. Too many
    others solve their problem after someone puts in a lot of work trying to help
    and the original poster responds with "Nevermind. I solved it." and leaves
    all of us wondering how the story ends.

    Glad you found your problem.

    Dale
     
    Dale, Apr 20, 2005
    #5
    1. Advertisements

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments (here). After that, you can post your question and our members will help you out.