user3758251
user3758251

Reputation: 65

JavaScript methods one works the other doesn't

Why does this work?

<script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>

<script type="text/javascript" >
$( document ).ready(function() {
$('#listF').on('change', function(){
    var n = this.getAttribute('size'),
        i = this.selectedIndex,
        l = this.options.length;
    this.selectedIndex = Math.min(l-1,i+n/2|0);
    this.selectedIndex = Math.max(0,i+1-n/2|0);
    this.selectedIndex = i;
});
    });
</script>


<select name="" id="listF" size="5">
    <option value="01">001</option>
    <option value="02">002</option>
    <option value="03">003</option>
    <option value="04">004</option>
    <option value="05">005</option>
    <option value="06">006</option>
    <option value="07">007</option>
    <option value="08">008</option>
    <option value="09">009</option>
    <option value="10">010</option>
</select>

and this does not work?

<script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>

<script type="text/javascript" >
function centerNumber(){
    var n = 5,
        i = this.selectedIndex,
        l = this.options.length;
    this.selectedIndex = Math.min(l-1,i+n/2|0);
    this.selectedIndex = Math.max(0,i+1-n/2|0);
    this.selectedIndex = i;
}
</script>


<select name="" id="listF" size="5" onchange="centerNumber()">
    <option value="01">001</option>
    <option value="02">002</option>
    <option value="03">003</option>
    <option value="04">004</option>
    <option value="05">005</option>
    <option value="06">006</option>
    <option value="07">007</option>
    <option value="08">008</option>
    <option value="09">009</option>
    <option value="10">010</option>

I prefer the second method as it can be used plenty of times not just one. In the first method you must copy/paste the code at each time you need to change. The second method seems cleaner.

What I mean in it doesn't work is that it does not centre. The JavaScript seems to fail to work.

Upvotes: 0

Views: 94

Answers (5)

RobG
RobG

Reputation: 147453

Lots of good advice. You can also do it without jQuery (or any library), some options:

  // Things that work in all browsers
  window.onload = function() {
    document.getElementById('listF').onchange = centerNumber;
  }

  // Place in a script element just before the closing body tag
  document.getElementById('listF').onchange = centerNumber;

  // Things that work in most, but not all, browsers
  // IE 8 and lower don't support addEventListener
  // There are plenty of cross-browser alternatives
  window.onload = function() {
    document.getElementById('listF').addEventListener('change', centerNumber, false);
  }

There are lots of questions and answers on SO about attaching event listeners. It doesn't take long before inline listeners become a headache, but for a simple site they're just fine.

Upvotes: 0

Paritosh
Paritosh

Reputation: 555

If you will call centerNumber() method with 'this' as a parameter then this will work. e.g.,

<select name="" id="listF" size="5" onchange="centerNumber(this)">


<script type="text/javascript" >
    function centerNumber(which){
        var n = 5,
        i = which.selectedIndex,
        l = which.options.length;
        which.selectedIndex = Math.min(l-1,i+n/2|0);
        which.selectedIndex = Math.max(0,i+1-n/2|0);
        which.selectedIndex = i;
    }
</script>

Upvotes: 0

Quentin
Quentin

Reputation: 944114

The value of this depends on how a function is called.

In the first example the anonymous function expression you pass to on is the event handler, so when it gets called it is in the context of the element.

In the second example, onchange is the event handler (which doesn't use this at all) and it calls centerNumber with no context (so it gets the default context of window).


I prefer the second method

Don't. Embedding JS in HTML and using globals is how we did things in the 90s. It is far cleaner to separate concerns and package code into narrow scopes to avoid conflicts.

as it can be used plenty of times not just one. In the first method you must copy/paste the code at each time you need to change.

That is not true. Just define a function first and reuse it.

function someFunction (event) { 
    /* do stuff */ 
};

jQuery('.someElements').on('change', someFunction);
jQuery('#anElement').on('click', someFunction);

Upvotes: 4

Guffa
Guffa

Reputation: 700630

The second script doesn't work because this doesn't point to the element.

In the event handler this is the element, but then you call a function so you lose the context. You can use the call method to specify the context for the function:

onchange="centerNumber.call(this)"

You can use the first approach with multiple elements also, just specify them in the selector. Example:

$('#listA,#listB,#listC,#listD,#listE,#listF').on('change', function(){

Using a class to target the elements makes it even easier, as you can set the same class on multiple elements.

Upvotes: 0

Alnitak
Alnitak

Reputation: 339955

You shouldn't use the second method - inline DOM0 event handlers are error prone and old-fashioned. The specific problem you have is that you don't pass a correct this to the centering function.

By all means do put the handler in a separate named function so that it can be re-used on multiple elements (as you did in the second code) but then you should use jQuery to register it:

$('#listF').on('change', centerNumber);

Upvotes: 0

Related Questions