0

I have a for loop that iterates over dependent fields in a form. The array looks like this:

var dependentFields = [
    { parent: FLDID_LABEL, children: [FLDID_LABEL_TEMPLATE, FLDID_LABEL_INSTRUCTIONS], choiceTrigger: 'Yes', markAsReq: true },
    { parent: FLDID_SHIP_TO, children: [FLDID_SHIP_TO_ADDR], choiceTrigger: 'No', markAsReq: true }
];

I have a function that gets called to attach all the event handlers. For simplicity, I will show just the loop where the problem is occurring.

function attachEventHandlers() {
    // begin dependent fields
    for (var i = 0; i < dependentFields.length; i++) {
        var o = dependentFields[i];
        $('#' + o.parent).change(function () {
            var visible = $('#' + o.parent + ' :selected').text() === o.choiceTrigger;
            for (var c = 0; c < o.children.length; c++) {
                var child = o.children[c];
                showField(child, visible);
                if (o.markAsReq && $('#' + child).val() === '') {
                    MarkFieldAsRequired(child);
                }
            }
        });
    }
}

Only the second dependent field works and the first one does not. I think this is related to the way var i or var o is referenced from the outer function. Effectively the same event handler gets attached to all the dependent fields. How can I fix this?

EDIT: Here is a jsfiddle with the bug: http://jsfiddle.net/H3Bv2/4/ Notice how changing either of the parents only affects the second child.

styfle
  • 22,361
  • 27
  • 86
  • 128
  • Can you set up a [fiddle](http://www.jsfiddle.net)? Looking at this, it seems like your bindings are correct. – davehale23 Oct 12 '12 at 20:15

2 Answers2

1

Take a look at the solutions here: JavaScript closure inside loops – simple practical example.

Your original code refers to a single variable o in every callback function that's created in the loop - and the value of that variable is reassigned on every iteration, so all of the callbacks end up using the last value assigned.

Community
  • 1
  • 1
kpozin
  • 25,691
  • 19
  • 57
  • 76
  • I didn't mark this as the correct answer because you didn't answer the question. I knew what the problem was. But I'm upvoting for the relevant link. – styfle Nov 21 '12 at 20:09
0

I figured it out. Using jQuery.each let me avoid defining variables in the loop. Here is my solution:

function attachEventHandlers() {
    // begin dependent fields
    $.each(dependentFields, function (i, o) {
        $('#' + o.parent).change(function () {
            var visible = $(':selected', this).text() === o.choiceTrigger;
            for (var c = 0; c < o.children.length; c++) {
                var child = o.children[c];
                showField(child, visible);
                if (o.markAsReq && $('#' + child).val() === '') {
                    MarkFieldAsRequired(child);
                }
            }
        });
    });
}
styfle
  • 22,361
  • 27
  • 86
  • 128