Juan Jo
Juan Jo

Reputation: 892

Javascript addEventListener for two different elements conflict

I have to prevent empty search submit on search forms. Forms does not have submit buttons, so I have to prevent the enter.

The html code:

Form 1

 <form method="get" class="search-form" id="searchform" action="http://example.com" >   
                <input class="text" name="s" id="s" type="text" />       
    </form>

Form 2

<form action="http://example.com" class="search-form" method="get">             
    <input type="text" name="s" class="text">                           
</form>

The Javascript code

// Im sure this funcions returns the 2 different forms, 
var searchForms = getElementsByClass('search-form');    
    for(i in searchForms)
    {   
        if (searchForms[i].addEventListener) 
        {
            searchForms[i].addEventListener("submit", function(e)
               {
                preventSubmit(e); // no problem here
                console.log(i) // ALWAYS LOGS 1         
               });
        } //I also implemented the ie code, but not necessary here, is the same as above for addEventListener
            
    }

Every time I submit any form, writes 1 in the console, any idea?

Upvotes: 0

Views: 1678

Answers (3)

Ajay Singh Beniwal
Ajay Singh Beniwal

Reputation: 19037

This is happening because of closure pls see similar link

Jquery dynamic buttons dialog for in loop doesn't populate function

Upvotes: 0

Andreas Louv
Andreas Louv

Reputation: 47099

You will need a closure:

var searchForms = getElementsByClass('search-form');    
    for(i in searchForms)
    {   
        if (searchForms[i].addEventListener) 
        {
            (function(i) { // Closure start <-- We make our own static variable i 
                searchForms[i].addEventListener("submit", function(e)
                   {
                   preventSubmit(e); // no problem here
                   console.log(i)        
                   });
            })(i); // Closure end.
        }
    }

It's because after your loop (for i in searchForms) i will be the last value (===1). You will need to make a closure to have a static value of i.

See more about closures here:

How do JavaScript closures work?

Upvotes: 4

Mitya
Mitya

Reputation: 34556

The callback is not executed until submit - by which time the value of i is 1. A closure, in the form of an immediately-executing function, allows us to capture the varying value of i and pass a copy of it in to our function.

Also

1) except in certain situations, generally avoid for-in loops over arrays. Use traditional for loops. If you were to use your present for-in having selected the forms via the ECMA5 querySelectorAll() method, for example, you would get unexpected results (four iterations of the loop, not two)

2) you are needlessly re-assessing which event registration mechanism to use for each iteration of the loop. Decide this once, outside.

//get forms
var searchForms = getElementsByClass('.search-form');

//initialise event registration depending on browser
var addEvent = window.addEventListener ? function(el, evt, func, bubble) {
    el.addEventListener(evt, func, bubble);
} : function(el, evt, func) {
    el.attachEvent('on'+evt, func);
};

//bind submit events
for (var i=0, len=searchForms.length; i<len; i++) {
    (function(i) {
        addEvent(searchForms[i], "submit", function(evt) { alert(i); preventSubmit(evt); }, false);
    })(i);
}

Upvotes: 1

Related Questions