Script works except in Safari and Chrome

Hallo all,

I’ve written some Javascript to do a few small things on a page, and was excited that it actually worked, even in IE!
…until I tested in Safari-for-Windows and Chrome on Windows and Linux. I’m going to assume Safari on a Mac also won’t run then.

I have a page with some forms. I need to grab the ones with an id starting with “formMaat” (may have a number after it), hide the submit button, and add an onchange event to the lone dropdown select in the form.

Safari and Chrome are removing the submit fine, so they are finding the forms ok.

The onchange event is just supposed to submit the form… I had to imitate the behaviour of the old site but make it accessible to those without JS.

I ended up using a closure to get the “form” passed to the select element because otherwise “form” was unknown… and I can’t tell if that’s maybe what’s tripping up Saffy-Chrome or not. I set a breakpoint in Chrome’s developer thingie but I can’t figure out how to see the script run when I click on the select.

One of the pages currently: http://stommepoes.nl/Jeansselling/jeansselling2/artikel-combo.html

The forms in question are on the right/main part of the page, where it says “maat:”.


          <form action="http://ishtml5readyyet.com/" method="get" id="formMaat">
            <fieldset>
            <legend><span>Kies een maat en krijg de juiste prijs en voorraadstatus</span></legend>
            <label for="maat">Maat: </label>
              <select id="maat" name="maat">
                <option value="10170">W 28 - L 28</option>
                <option value="10171">W 28 - L 31</option>
                <option value="10172">W 28 - L 34</option>
...
              </select>
              <input type="submit" value="Maat Kiezen" />
            </fieldset>
          </form>

(they are temporarily “get” so I can see them open a new page, but they will be “post”… and the action is temporarily a url for fun)

JS:


var JeansArtikel = {
    init: function() {

        for (var i=0, l=document.forms.length; i<l; i++) {
            //alleen forumilieren met id van "formMaat"-iets (1, 2, enz)
            var somePattern = /formMaat*/;

            if (somePattern.test(document.forms[i].id)) {
                var submit = document.forms[i].elements[document.forms[i].elements.length-1];
                $(submit).addClass('hidden');
                //alle formulieren zijn 3 elementen: undefined/fieldset, select-one, submit
                var optie = document.forms[i].elements[1];
                optie.onchange = function() { 
                    JeansArtikel.jsSubmitForm(optie); 
                };
                //was:
                /*optie.onchange = (function(optie) {
                    return function() {
                        JeansArtikel.jsSubmitForm(optie);
                    };
                })(optie); */
            }
        }
    },
    
    jsSubmitForm: function(optie) {
        alert('on change'); //test
        optie.form.submit();
    } 
};

$(document).ready(function() {
    JeansArtikel.init();
});

Since there’s a jQuery lightbox on the page, I’m using jQuery for loading, but this shouldn’t affect anything.

Now, am I being stupid just looping through forms instead of storing them in some vars?

Do I really need that closure? When I didn’t have it, optie.form.submit() or this.form.submit() did not run and I thought it should have, since “optie” was known… I thought “.form” would have just looked for that element’s form anyway, but it didn’t.
*edit tried a simpler way, but still no love from Saffy-Chrome.

I know I don’t need to really separate that function over to outside init, except who knows if later more events will need to trigger more weird stuff… so I’m trying to write safely.

Any information would be appreciated. …and I thought Safari and Chrome now have different Javascript engines?

Thanks

You’re not likely to have many forms on the page, so that’s fine. Since you already have jQuery on there, you could use that to simplify things, such as using the attribute starts with selector, and do stuff with the resulting items.


$('form[id^="formMaat"]').each(function () {
    ...
});

You shouldn’t need that closure. Any elements that have an event function are automatically accessible by the this keyword.

I’ve just tested it with just this.form.submit() in the function, and it seems works fine. Would you mind putting together a separate version of the page where it doesn’t work when you think that it should, so that we can test that out?

It’s kind of hard to work out why a working version of a page was not working when it had different code.

Even after posting, I continued working on it, so the url quickly changed from what I posted (which is why I posted the code I had at the time).

Anyway, I have narrowed the problem down: Firefox, IE and Opera believe there are three elements in my form: undefined (the fieldset I believe), select-one and submit.

However Chrome (and so likely Safari) only see two elements: select-one and submit.

So my problem was my not checking WHICH element was at
var optie = document.forms[i].elements[1];
since I dunno what’s normally in form.elements so I figured a weird undefined fieldset was normal. Guess it’s not universal.

What I’m going to try to do is look for the select-one element and assign “optie” to that… and then see if Saffy-Chrome are still giving me trouble.

Ok, thanks. There might be 4 at the most, and the last one is not to be used (search form).

Since you already have jQuery on there, you could use that to simplify things, such as using the attribute starts with selector, and do stuff with the resulting items.

I’m trying my hardest to avoid jQuery except where I need to… since it’s already dealing with onpageload for another script, I figured it would be stupid of me to load my own library. So I had to use the .addClass, but I’d like to keep this as Javascript as possible… I’ll go learn jQuery after I know Javascript, otherwise it’ll make no sense to me.

You shouldn’t need that closure. Any elements that have an event function are automatically accessible by the this keyword.

I had tried


optie.onchange = function() {  
    this.form.submit();
}

but when that didn’t work I went more and more complex. Lawlz, I tend to do that.

Would you mind putting together a separate version of the page where it doesn’t work when you think that it should, so that we can test that out?

Will do after type checking. If my problem is solved I’ll just post all the working code I have; if it’s not, I’ll post the separate page.

Thanks for the quick answer.

Aha, that was it. Some browsers count the fieldset and some don’t. wtf.

url is the same, HTML is unchanged from above.

Working code:


var JeansArtikel = {
    init: function() {

        var form;
        for (var i=0, l=document.forms.length; i<l; i++) {
            //alleen forumilieren met id van "formMaat"-iets (1, 2, enz)
            var somePattern = /formMaat*/;

            if (somePattern.test(document.forms[i].id)) {
                form = document.forms[i];
                var optie;
                var submit = form.elements[form.elements.length-1];
                $(submit).addClass('hidden');

                //vind select
                for (var j=0, k=form.elements.length; j<k; j++) {
                     if (form.elements[j].type === 'select-one') {
                         optie = form.elements[j];
                         optie.onchange = function() {  
                             this.form.submit();
                        }
                    }
                }
            }
        }
    } 
};

$(document).ready(function() {
    JeansArtikel.init();
});

I got tired of reading document.forms[i] so ended up giving it a variable.