Strange call behavior?

I’m a JS novice and SitePoint has been very useful in my self-education. I’m hoping to get more specific advice by joining the forum, and maybe one day will have advice to give.

I’ve built a simple web form for my site and used a JS function to clear each field’s initial value onfocus (and restore onblur):

function resetFields(whichform) {
for (var i=0; i<whichform.elements.length; i++) {
var element = whichform.elements[i];
if (element.type == “submit”) continue;
if (!element.defaultValue) continue;
element.onfocus = function() {
if (this.value == this.defaultValue) {
this.value = “”;
}
}
element.onblur = function() {
if (this.value == “”) {
this.value = this.defaultValue;
}
}
}
}

window.onload = prepareForms;
function prepareForms() {
for (var i=0; i<document.forms.length; i++) {
var thisform = document.forms[i];
resetFields(thisform);
}
}

I built the form in its own html document and tested this in most browsers; it works well. But when I add it to my site, where the form is in an initially hidden layer, the script doesn’t work. I assumed that the call function had broken down for some reason and so tried removing the window.onload call and assigned an MM_callJS function to the form itself onfocus… no luck.

I’m aware that there may be some issue with the hidden form not being recognized by the resetFields function, but I really don’t know where to go from here.

And I have to say that I really don’t see why the script isn’t running in all forms on the page hidden or visible.

Any enlightenment is GREATLY appreciated.

Mr. Wilkins, you are a gentleman and a savior. Everything is running smoothly now and I appreciate knowing that I can call functions from the bottom of the page; it never occurred to me to organize that way but I’m already seeing improvements.

Sincere thanks.

Let’s get testing.

Here is an initially hidden layer:


<p><a id="toggle" href="#hidden">Toggle hidden layer</a></p>
<div id="hidden">
    <form>
        <p><label>Name: <input name="name" value="Name"></label></p>
        <p><label>Email: <input name="email" value="Email"></label></p>
    </form>
</div>

And here is a script at the end of the body, that sets up the toggle layer, and hides it before the page is loaded.



(function () {
    var toggle = document.getElementById('toggle');
    toggle.onclick = function toggle () {
        var id, el;
        id = this.href.split('#')[1];
        el = document.getElementById(id);
        if (el.style.display === 'none') {
            el.style.display = '';
        } else {
            el.style.display = 'none';
        }
    };
    toggle.onclick(); // hide it before the page is loaded
})();

Your code works perfectly fine on this test page, so now we need to look at your test page to find out what there is on there that is conflicting with how it’s expected to work.

Good job, that’s perhaps the best way of testing.

The problem is that window.onload occurs only once. If a script changes it, the old setting is destroyed.

You may find it better to not use window.onload and to use one of the cross-browser techniques to attach events instead. Or perhaps even better, you can move the script to the bottom of the body, just before the </body> tag, so that you can successfully run the script before even the onload event takes place.


<body>
    ...
    <script type="text/javascript" src="js/script.js"></script>
</body>

That’s also one of the best practices for speeding up your web site.

So all you’d need there is:


P7_fixSafariBB();
prepareForms();

But there’s no reason at all why you shouldn’t put all of your scripts at the bottom.

I started with your code, Paul, and changed / added elements until I had built the exact form I’m having trouble with, testing it with every change… It turns out that issue is a conflict with another function that I use to debug the Safari browser’s ‘back’ button.

window.onload = P7_fixSafariBB;
function P7_fixSafariBB(){ //v1.1 by PVII
if(navigator.userAgent.indexOf(“Safari”)>-1){
var jj=onload;if(jj){if(onunload==null){
document.body.setAttribute(‘onunload’,jj);}}}
}

I thought that this might simply preventing the prepareForms function because they are both called by window.onload, so I tried calling P7_fixSafariBB with <body onload=…>, but prepareForms was still negated.

Could there be a conflict in the actual functions that I’m not seeing?