0

I have a website containing a lot of different contact forms. I want to keep an array of their ID's (and other related settings) so I can loop through them and add submit handlers to each one.

The problem is that only the last form in the array seems to get a handler attached to it.

List of forms:

forms = [
    {id: '#contact-form-1', ...},
    {id: '#contact-form-2', ...}
]

How I'm trying to add submit handlers:

for (i in forms) {
    $(document).on('submit', forms[i].id, function(){
        // Validation, send email etc.
    }
}

Is $(document).on() the right way to approach this? I have tried $(forms[i].id).submit(); but I get the same outcome; only the last form in the list gets bound to.

James Cook
  • 95
  • 1
  • 6
  • The problem is that all the handlers share the same variable "i". The event handler will be invoked such that `this` refers to the form instance when the handler is called, so you probably don't need to use "i" in the handlers anyway. – Pointy May 18 '14 at 12:25
  • In fact you may be able to do what you need with just one blanket handler that works for all forms on the page. – Pointy May 18 '14 at 12:25
  • Are you binding the same function to *all* of them? Because if you are you're making this needlessly-complex and could use `$('form[id^="contact-form-"]')` or simply switch to a class-name: `$('form.contact-form')`. – David Thomas May 18 '14 at 13:10
  • There's different UI things associated with each one otherwise I would have definitely done it this way. Much easier than maintaining a list of forms! – James Cook May 18 '14 at 14:18

2 Answers2

1

Might want to do this the other way round.

/* listen for ALL submit forms */
$('form').on('submit', function() {

  /* get the id of the this one */
   var _id = $(this).attr('id');

    /* do some conditions on _ID */


));

So say your objects was like :

var formIDs = {
      formidOne: { func : function() { alert('called form id one'); }},
      formidTwo: { func : function() { alert('called form id two'); }}
    };

Then could do say:

$('form').on('submit', function() {

  /* get the id of the this one */
   var _id = $(this).attr('id');

    /* call the form function associated with this form id */
    formIDs[_id].func();

));

A few ways to do this, all depends how you want to organise your code , this would be a little easier as only defining the listener once


Adding an edit : as not really explained what is going wrong in your original code - which is that the context of i is not retained correctly ( already hinted in a comment )

The solution is to make use of another function :

function makeHandler (index) {
 $('#'+forms[index].id).on('submit', function(){... });
}

for (i in forms) {  makeHandler(i); }

This is the best place to look up problems around making functions in a loop - How to fix jslint error 'Don't make functions within a loop.'?


Would still favour using one handler as above, easier to maintain / read ( imo )

Community
  • 1
  • 1
Rob Sedgwick
  • 5,216
  • 4
  • 20
  • 36
1

You can do it from within a closure like $.each.

$.each(forms, function(index, item){
   $(document).on('submit', forms[index].id, function(){.....

})

Without jQuery can create closure of for loop index doing:

for (i in forms) {

    (function(i){
       /* your code here */
     })(i);
}
charlietfl
  • 170,828
  • 13
  • 121
  • 150
  • 1
    `for in` should be [avoided for object traversal](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...in) or the property checked with `hasOwnProperty()`.. – nietonfir May 18 '14 at 13:04