0

I'm trying to create "dynamic" cascading dropboxes, and I almost have it done. However, I'm running into an issue dealing with adding a .change() listener onto every variable inside of an array that contains the <select> field ids.

So if I use:

fields[0].change(function() {populateFields(1, 0, xml);});
fields[1].change(function() {populateFields(2, 1, xml);});

The code works perfectly. However, I would prefer to use something like this:

for (i=1; i<numberOfFields; i++){
            p = i-1; current = i;
            fields[p].change(function() {populateFields(current, p, xml);});
        }

So that I can have a variable number of fields, because the current code is limited to three fields. The for loop currently works, but doesn't work after the second field is entered.

Any help would be appreciated.

NOTE: This is not a question about variables or passing variables into functions, but rather adding a event listener to an array. The marked answer was the correct answer.

Blaise
  • 330
  • 1
  • 11
  • I should mention that the reason I am starting the for loop on 1 is because the 0 index has different programming and is handled elsewhere. So this is for fields[1]=model, and fields[2]=year – Blaise Jan 27 '17 at 01:21
  • is it just for indices 1 and 2? – hackerrdave Jan 27 '17 at 01:22
  • if you start at i=1, then the `if` condition will never get hit, and therefor is not needed – hackerrdave Jan 27 '17 at 01:23
  • Haha. That's true. It would be for indices 1, 2, .... n – Blaise Jan 27 '17 at 01:25
  • I've removed the if statement – Blaise Jan 27 '17 at 01:27
  • should `current` really be `i + 1`? or should your first code be: `fields[1].change(function() {populateFields(1, 0, xml);});` – hackerrdave Jan 27 '17 at 01:29
  • Why don't you give all the elements a class so you can write `$('.className').change(...)` instead of writing a loop? – Barmar Jan 27 '17 at 01:56
  • Because the entire form is made dynamically. It's a php function that takes the fields as an array parameter. I don't necessarily know what the names are, because they could be different every time. – Blaise Jan 27 '17 at 02:03

1 Answers1

1

You can use Array.prototype.forEach(), and in the function that you pass in you can put a guard for the case where you are processing the first element:

fields.forEach(attachChangeHandler);

function attachChangeHandler(field, i) {
  if (i === 0) { return; }
  field.change(function() {
    populateFields(i + 1, i, xml);
  });
}
hackerrdave
  • 6,486
  • 1
  • 25
  • 29
  • That looks really promising. How is field defined in the attachChangeHandler function? – Blaise Jan 27 '17 at 01:34
  • 1
    @Blaisen `forEach` will invoke the function for each element in the array, passing in the parameters. The duplicate question has more information. – 4castle Jan 27 '17 at 01:36
  • the function passed into `forEach` will have args for: element of array, index, array. so in this case the field represents each iterated element in the array – hackerrdave Jan 27 '17 at 01:36
  • 1
    This works! One edit, was the if (i === 0) { return; } was unnecessary! Thanks! – Blaise Jan 27 '17 at 01:42