RegisterStartupScript firing at the wrong time

L

lisa

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?
 
D

Dale

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
 
L

lisa

Dale said:
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?)

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.
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;

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
 
L

lisa

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
 
D

Dale

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
 

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. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,904
Latest member
HealthyVisionsCBDPrice

Latest Threads

Top