1

I have a problem with my jQuery script and Safari (Mac + iPhone). This is the structure of the page: Structure

As I need to modify the data before sending it to the next script, I read all of the forms (serializeArray), modify it to my needs, write them in a new form (display:none) and let it send to the next page. This is the script:

$("input#newsubmit").click(function(e) {
    e.preventDefault();
    arraytix = [];
    checkboxStatus = 0;
    $("input[id^=field]").each(function(i) {
         if ($(this).val() != 0) {
              arraytix[i] = $(this).attr('name') + ":" + $(this).val() + ":" + $(this).parent().parent().find("li.four").find("input[id*=price_item]").val() + ":" + $(this).parent().parent().find("li.five").find("input[id*=vvk_item]").val();
         }
    });

    var carttix = '';
    jQuery.each(arraytix, function(i) {
         if (arraytix.hasOwnProperty(i)) {
             if (i == arraytix.length - 1) {
                 carttix += this;
             } else {
                 carttix += this + '-';
             }
         }
    });

    $("form#finalSubmit").append( '<input name="cart" value="'+carttix+'" />');
    $("form#finalSubmit").append( '<input name="versand" value="'+$("select#item_vat_1").val()+'" />');
    $("form#finalSubmit").append( '<input name="barzahlung" value="'+checkboxStatus+'" />');
    if (checkboxStatus == 0) { 
         var fields = $("fieldset.customer").serializeArray();
         alert("before each");
         jQuery.each(fields, function(i, field){
             $("form#finalSubmit").append( '<input name="'+field.name+'" value="'+field.value+'" />');
             alert("loop");
         });
         alert("after jquery.each");
    }
    //$("form#finalSubmit").submit();
}

The first instance of jQuery.each works as expected on all browsers and plattforms. The second instance of jQuery.each with the append command doesn't execute on Safari on all plattforms.

For debugging purpose I have added some alerts. Mac with Safari: alert("before each") and alert("after each") get triggered, jQuery.each doens't. Other browsers (including Firefox Mac) haven't got any problem. The first alert, some alert("loop")s and the last alert fire up as it should be.

What is the problem here?

MukMuk
  • 166
  • 11
  • Have you tried your second instance on multiple other browsers? Always try cross checking to see if its a problem with the browser. – SamCyanide Oct 17 '13 at 16:51
  • FYI: you don't need the `if (arraytix.hasOwnProperty(i)) {` check. I'm not even sure how that would work (checking an array for whether it has a property equal to the current index?). It's good to do for objects, but all you have a regularly indexed array. If you remove that, you might have to change `arraytix[i] = ...` to `arraytix.push(...)`. – Cᴏʀʏ Oct 17 '13 at 16:55
  • 1
    Isn't your second loop equivalent to `carttix = arraytix.join('-')`? – Barmar Oct 17 '13 at 16:58
  • @Cory `arraytix.hasOwnProperty()` will filter out the unassigned array elements because it's a sparse array. – Barmar Oct 17 '13 at 17:02
  • Actually, it's not equivalent. `join` will include all the unassigned array elements, not skip them. I'm surprised. The code would be greatly simplified if you just used `arraytix.push()` instead of assigning `arraytix[i]`. Do you really need a sparse array like this? – Barmar Oct 17 '13 at 17:05
  • Is there any reason you're building the inputs like this, and not just submitting what is on the screen and assembling it on the server? What does `fields` look like? Do its elements actually have `name` and 'value` properties? – Cᴏʀʏ Oct 17 '13 at 17:11

1 Answers1

1

serializeArray(), according to a little bit of Googling, is normally only supposed to work on actual form or input elements. Right now, you're basically trying to ask it to serialize a fieldset. Try changing your serializeArray() line to:

var fields = $("fieldset.customer :input").serializeArray();

I think you can make this code quite a bit clearer as well. I've added notes where I think you should be investigating and/or learning. There's nothing jQuery-wise that shouldn't be working in the browsers you mentioned, at least not that I can see. I've made the above-mentioned change in the code below as well:

$("#newsubmit").click(function(e) { // just the ID is faster than including the element type
    e.preventDefault();

    var arraytix = [], // added "var" to stay in local scope
        checkboxStatus = 0; // where does this get set? It's always 0

    $("input[id^=field]").each(function() { // you don't need 'i' anymore
         // find some things up front so you're not asking jQuery to
         // find them over and over again
         var $this = $(this),
             $grandParent = $this.parent().parent(),
             val = $this.val();

         if (val !== "0") { // val() usually returns a string
              // use push() to avoid creating a sparse array
              arraytix.push([
                  $this.attr('name'),
                  val, 
                  $grandParent.find("li.four").find("input[id*=price_item]").val(),      
                  $grandParent.find("li.five").find("input[id*=vvk_item]").val()
             ].join(':')); // forget about adding those colons manually
         }
    });

    // join the entries with a hyphen
    var carttix = arraytix.join('-');

    // append your elements; jquery doesn't need you to close your tags
    var $form = $('#finalSubmit'); // again, no element type in selector
    // chain calls where you can
    $form 
        .append('<input name="cart" value="'+carttix+'">')
        .append('<input name="versand" value="'+$("#item_vat_1").val()+'">')
        .append('<input name="barzahlung" value="'+checkboxStatus+'">');

    // This is always 0 -- are you setting it somewhere else?
    if (checkboxStatus == 0) { 
         // serializeArray is only supposed to work on actual input elements
         // adjusted below:
         var fields = $("fieldset.customer :input").serializeArray();
         console.log("before each");
         // Make sure fields is in the format you're expecting
         console.log(fields);
         $.each(fields, function() {
             $form.append( '<input name="'+this.name+'" value="'+this.value+'">');
             console.log("loop");
         });
         console.log("after jquery.each");
    }

    //$form.submit();
}

I changed your alerts to console.log. You can inspect the actual elements in a proper debugging tool like Firebug or Chrome's console (hit F12 in most browsers to open their consoles).

Cᴏʀʏ
  • 105,112
  • 20
  • 162
  • 194
  • thanks for cleaning the code! $checkboxStatus gets changed with an other script. it's a pretty simple if-function. the problem still exists. the jQuery.each-function with fields is running great on windows' browsers, and firefox for mac. on safari mac it shows "**before each**" "**[]**" "**after jquery.each**" still no console.log output for fields and "loop". – MukMuk Oct 17 '13 at 17:47
  • @MukMuk: `serializeArray()` is supposed to be used on a `form` element. It does not work on fieldsets in Safari ([see this](http://stackoverflow.com/questions/14852842/jquery-serializearray-doesnt-work-in-safari?rq=1)). – Cᴏʀʏ Oct 17 '13 at 20:18
  • You can probably change your selector to: `var fields = $('fieldset.customer :input').serializeArray();`. I'll edit my answer. – Cᴏʀʏ Oct 17 '13 at 20:26
  • Yep, that `:input` was it! Thanks for the optimized code, it works like a charm! – MukMuk Oct 21 '13 at 11:06