Plz Help in this code


#1

I cannot find out what’s wrong in this code.

The idea is that if we click on the input bar, the paragraph above should assist by displaying messages.

Only the last message is displayed no matter which bar I click.

I was reading about Closures and tested out this code but this one isn’t working.

<p id="help">Helpful notes will appear here</p>
<p>E-mail: <input type="text" id="email" name="email"></p>
<p>Name: <input type="text" id="name" name="name"></p>
<p>Age: <input type="text" id="age" name="age"></p>

<script>
function showHelp(help) {
  document.getElementById('help').innerHTML = help;
}

document.getElementById('email').onfocus = showHelp('Your e-mail address')
document.getElementById('name').onfocus = showHelp('Your full name')
document.getElementById('age').onfocus = showHelp('Your age')
</script>


#2

the onfocus event requires a function to execute when focus is set, not a function call.

so then you get:

document.getElementById('email').onfocus = function(){showHelp('Your e-mail address')}

function() is a anonymous function expression.


#3

Yeah ur right. Silly mistake. Thanks :+1:


#4

There must be a more efficient way to do this, it feels like we we are violating DRY principal at the moment.


#5

Actually I am reading the whole MDN (From HTML to all the way to JS) so I was reading closures https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures

So there they were explaining why you should not create closures in the for loop.
I was comparing MDN with what I read in JavaScript: The definitive Guide by David Flannagan.

Both of them had similar examples so I was just experimenting with them.

The code in MDN was:

function showHelp(help) {
  document.getElementById('help').innerHTML = help;
}

function setupHelp() {
  var helpText = [
      {'id': 'email', 'help': 'Your e-mail address'},
      {'id': 'name', 'help': 'Your full name'},
      {'id': 'age', 'help': 'Your age (you must be over 16)'}
    ];

  for (var i = 0; i < helpText.length; i++) {
    (function() {
       var item = helpText[i];
       document.getElementById(item.id).onfocus = function() {
         showHelp(item.help);
       }
    })(); // Immediate event listener attachment with the current value of item (preserved until iteration).
  }
}

setupHelp();

So the code above is the easiest way I could find to do the job.


#6

But the problem with your solution is that its not very good at adapting change

if we wanted to add a 4th input element, we need to make more changes to the code. MDN solution only involves adding the html element and an entry to the helpText array.


#7

Yeah ur right.

I didn’t understand why didn’t the code work so I kind of came up with my own.

This was their first example and I didn’t understand why it didn’t work:

function showHelp(help) {
  document.getElementById('help').innerHTML = help;
}

function setupHelp() {
  var helpText = [
      {'id': 'email', 'help': 'Your e-mail address'},
      {'id': 'name', 'help': 'Your full name'},
      {'id': 'age', 'help': 'Your age (you must be over 16)'}
    ];

  for (var i = 0; i < helpText.length; i++) {
    var item = helpText[i];
    document.getElementById(item.id).onfocus = function() {
      showHelp(item.help);
    }
  }
}

setupHelp();

Related to closures. I will reread the thing…


#8

its explained here:

The reason for this is that the functions assigned to onfocus are closures; they consist of the function definition and the captured environment from the setupHelp function’s scope. Three closures have been created by the loop, but each one shares the same single lexical environment, which has a variable with changing values (item.help). The value of item.help is determined when the onfocus callbacks are executed. Because the loop has already run its course by that time, the item variable object (shared by all three closures) has been left pointing to the last entry in the helpText list.

but i am struggling with it as well. Js never was my strong suit.

the problem seems to be scope of item variable, look:

for (var i = 0; i < helpText.length; i++) {
    var item = helpText[i];
    document.getElementById(item.id).onfocus = function() {
      showHelp(item.help);
    }
  }
  console.log(item);

if we log item to the console, we it contains the last entry/value. So it simply points the last item.


#9

I’m trying to understand how did we assign 3 functions to onfocus?

I thought we assigned 2 functions. First is the function definition which will return showHelp function when invoked by the focus event and second is the showHelp function (within the function definition) which will refer to it’s scope when it was defined.

I still don’t understand what I’m missing.


#10

the for loop runs 3 times? In each iteration of the loop we assign a onfocus event


#11

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.