-1

i realise this is probably classed as a duplicate however I've read this question and the replies in detail but still can't get my head around it.

I have this code, but within the 'focus' function, 'i' is always 2, (the pageSearchInput.length value), and I want it to be 0,1 respectively on each loop.

I understand that this is a scoping issue but I can't work out how to fix this without simply using 'let'.

If someone could explain how this works i'd be very grateful.

for (i = 0; i < pageSearchInput.length; i++) {

    pageSearchInput[i].addEventListener("focus", function(){

        pageSearchContainer[i].style.outline = "4px solid #ffcc33";
        pageSearchButton[i].style.backgroundColor = "#008920";
        pageSearchButton[i].style.border = "1px solid #008920";

    });

}
8
  • Im not sure, to be honest, but maybe define var i outside of the loop? Commented Aug 9, 2018 at 11:50
  • @ArthurWietzorek it may be defined outside the loop already? Commented Aug 9, 2018 at 11:51
  • Why wouldn't you just use let? This is one of let's main reasons for existing. Commented Aug 9, 2018 at 11:54
  • Because it isn't supported on IE10 or lower, and the website I'm making needs to. This question has been marked as duplicate for a 'let' question, when I've explicitly said I don't want to use it in the question. Slightly trigger happy Commented Aug 9, 2018 at 11:56
  • It's because i is incremented until it is pageSearchInput.length - 1 and the loop terminates. Then at some point in the future the event listener is executed, using the value of i *at that point in time. Wrap the code inside in a function that takes a parameter and pass in i` and it will execute as expected. Commented Aug 9, 2018 at 11:56

5 Answers 5

1

Just make i a parameter to the function and pass it, and return the function that handles the event:

for (i = 0; i < pageSearchInput.length; i++) {

    pageSearchInput[i].addEventListener("focus", (function(i){
      return function() {
        pageSearchContainer[i].style.outline = "4px solid #ffcc33";
        pageSearchButton[i].style.backgroundColor = "#008920";
        pageSearchButton[i].style.border = "1px solid #008920";
      };
    })(i));

}
Sign up to request clarification or add additional context in comments.

Comments

1

If you don't want to use let you should create a wrapping function.

for (i = 0; i < pageSearchInput.length; i++) {


    pageSearchInput[i].addEventListener("focus", function(){
        return (function(i) {
            pageSearchContainer[i].style.outline = "4px solid #ffcc33";
            pageSearchButton[i].style.backgroundColor = "#008920";
            pageSearchButton[i].style.border = "1px solid #008920";
        })(i);
    });

}

Comments

1

You can use IIFE (Immediately Invoked Function Expression)

(function () {
  statements
})();

It is a design pattern which is also known as a Self-Executing Anonymous Function and contains two major parts. The first is the anonymous function with lexical scope enclosed within the Grouping Operator (). This prevents accessing variables within the IIFE idiom as well as polluting the global scope.

The second part creates the immediately executing function expression () through which the JavaScript engine will directly interpret the function.

With IIFE your code should be:

for (i = 0; i < pageSearchInput.length; i++) {
  (function(i){
     pageSearchInput[i].addEventListener("focus", function(){

       pageSearchContainer[i].style.outline = "4px solid #ffcc33";
       pageSearchButton[i].style.backgroundColor = "#008920";
       pageSearchButton[i].style.border = "1px solid #008920";

    });
  })(i);
}

Comments

0

You have to use let keyword in order to preserve the value of i in the for loop scope.

for (let i = 0; i < pageSearchInput.length; i++) {

Another method is to use Immediately-invoked function expression

(function(i){
   pageSearchInput[i].addEventListener("focus", function(){

   });
})(i);

3 Comments

Thanks, but I said in the question I don't want to use let. The code needs to be IE compatible
@paddyfields that's what transpilers are for.
@paddyfields, i update my answer.
0

You can try to use IIFE to get your problem fixed related to scope.

for (i = 0; i < pageSearchInput.length; i++) {
   (function(j){
    return pageSearchInput[j].addEventListener("focus", function(){

        pageSearchContainer[j].style.outline = "4px solid #ffcc33";
        pageSearchButton[j].style.backgroundColor = "#008920";
        pageSearchButton[j].style.border = "1px solid #008920";

    })
  }(i))

}

For details find the explanation in this post http://learnwebtechs.com/2018/05/11/understanding-javascript-closures-with-example

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.