SitePoint Sponsor

User Tag List

Results 1 to 6 of 6
  1. #1
    SitePoint Enthusiast
    Join Date
    Dec 2009
    Posts
    26
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    Unhappy mass add event handlers to objects in array

    I am trying to add onclick event handler to many objects but I can't understand why it doesn't work.

    I would appreciate nothing too advanced. To assign event handler I use traditional approach as described in http://www.quirksmode.org/js/events_tradmod.html

    Heres the code (extract.js):
    Code JavaScript:
    //the class
    function extract(){
    	this.iForm=document.getElementById('iNew')
    	this.navSel=new Array()
    	this.x=0
    	this.navSel[this.x]=new Array(3)
    	this.navSel[this.x][0]=this.iForm.iVarrantyYears
    	this.navSel[this.x][1]=document.getElementById('nSel')
    	this.navSel[this.x][2]=document.getElementById('pSel')
    	this.x++
    	this.navSel[this.x]=new Array(3)
    	this.navSel[this.x][0]=this.iForm.bFloors
    	this.navSel[this.x][1]=document.getElementById('nSel2')
    	this.navSel[this.x][2]=document.getElementById('pSel2')
     
    	this.selectNext=function(select){
    		if(select.selectedIndex<select.length){select.selectedIndex+=1}
    	}
    	this.selectPrevious=function(select){
    		if(select.selectedIndex>=1){select.selectedIndex-=1}
    	}
    }
    //function to execute onload
    function prepare(){
    	o=new extract()
    	var c=o.navSel.length
    	for(i=0;i<c;i++){
    		//The following does NOT work
    		o.navSel[i][1].onclick=function(){o.selectNext(o.navSel[i][0])}
    		o.navSel[i][2].onclick=function(){o.selectPrevious(o.navSel[i][0])}
    	}
    	//The following approach works
    	/*
    	o.navSel[0][1].onclick=function(){o.selectNext(o.navSel[0][0])}
    	o.navSel[0][2].onclick=function(){o.selectPrevious(o.navSel[0][0])}
    	o.navSel[1][1].onclick=function(){o.selectNext(o.navSel[1][0])}
    	o.navSel[1][2].onclick=function(){o.selectPrevious(o.navSel[1][0])}
    	*/
    	//But obviously I want to add event automatically
    }

    This JavaScript code is used in extract.html (excerpt):
    Code HTML4Strict:
    <html><head>
    <script type="text/javascript" src="extract.js"></script>
    </head><body onload="prepare()">
    <form action="" method="post" id="iNew">
    <p>Years of Varranty: <select name="iVarrantyYears" /></select>
    <input type="button" id="nSel" value="+" />
    <input type="button" id="pSel" value="-" /></p>
     
    <p>Floor count in the building: <select name="bFloors" /></select>
    <input type="button" id="nSel2" value="+" />
    <input type="button" id="pSel2" value="-" /></p>
    </form>
    </body></html>

    I know that both select tags don't have options, but I generate them with JS because they hold sequential numbers and this part has no impact on the problem at hand.
    Both functions help select next or previous index in a given select tag for greater comfort

    Thanks!

  2. #2
    Unobtrusively zen silver trophybronze trophy
    paul_wilkins's Avatar
    Join Date
    Jan 2007
    Location
    Christchurch, New Zealand
    Posts
    14,527
    Mentioned
    84 Post(s)
    Tagged
    4 Thread(s)
    Inside the attached function, the variable i does not have the value that you think it has.
    By the time the event occurs, the variable i will always be the same number, that being the length of the array.

    Do not create the function from inside the loop. Instead, pass the variables o and i to a function that returns the appropriate function instead.

    Code javascript:
    function selectNextHandler(obj, index) {
        return function () {
            obj.selectNext(obj.navSel[index][0]);
        }
    }
    function selectPreviousHandler(obj, index) {
        return function () {
            obj.selectPrevious(obj.navSel[index][0]);
        }
    }
    ...
    for (...) {
        o.navSel[i][1].onclick = selectNextHandler(o, i);
        o.navSel[i][2].onclick = selectPreviousHandler(o, i);
    }


    Because the variables are now more removed from their context, I have also renamed o and i to be obj and index within the external functions.
    Programming Group Advisor
    Reference: JavaScript, Quirksmode Validate: HTML Validation, JSLint
    Car is to Carpet as Java is to JavaScript

  3. #3
    SitePoint Enthusiast
    Join Date
    Dec 2009
    Posts
    26
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    Smile

    Yes, that works! Thank you.

    A minor detail remains: how to make this code feel more OOP like. I know JS is not like that but defining two separate functions along the one necessary "prepare()" that is called after onLoad so that all the defined "getElementById" actually work - is there a neat approach? Because those functions have hard-coded variable names anyway - function name "selectNext" and array name "navSel" won't wokr for different objects.

    I noticed the scope problem after some time but my quick fix didn't work:
    o.navSel[i][1].onclick=function(e,i){o.selectNext(o.navSel[i][0])}
    o.navSel[i][2].onclick=function(e,i){o.selectPrevious(o.navSel[i][0])}

    Anyway great stuff. It's always hard to get hung up over syntax errors.

  4. #4
    Unobtrusively zen silver trophybronze trophy
    paul_wilkins's Avatar
    Join Date
    Jan 2007
    Location
    Christchurch, New Zealand
    Posts
    14,527
    Mentioned
    84 Post(s)
    Tagged
    4 Thread(s)
    You could always do it this way, so that the inner function retains the scope of the outer one.

    Code javascript:
    o.navSel[i][1].onclick = function(){
        return function () {
            o.selectNext(o.navSel[i][0]);
        }
    }(i);
    o.navSel[i][2].onclick=function(){
        return function () {
            o.selectPrevious(o.navSel[i][0]);
        }
    }(i);
    Programming Group Advisor
    Reference: JavaScript, Quirksmode Validate: HTML Validation, JSLint
    Car is to Carpet as Java is to JavaScript

  5. #5
    SitePoint Enthusiast
    Join Date
    Dec 2009
    Posts
    26
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    Lightbulb

    I couldn't get your code to work. Could you demonstrate using function as return value?

    Similar example: selecting radio button fires an event
    Javascript (extract.js)
    Code JavaScript:
    //the class
    function extract(){
        this.catRadio=document.getElementById('radioCat')
     
    	this.before_filter=function(){
    		//here, this assignment didn't work for me
    		this.catRadio.onclick=function(){
    			return function(){
    				o.yuba(o.catRadio,'drop')
    			}
    		}
    	}
     
    	this.yuba=function(radio,msg){
    		alert('value is '+radio.value+'\nmessage reads '+msg)
    	}
    }
    //function to execute onload
    function prepare(){
        o=new extract()
    	o.before_filter()
    }

    HTML
    Code HTML4Strict:
    <html><head>
    <script type="text/javascript" src="extract.js"></script>
    </head><body onload="prepare()">
    <form action="" method="post" id="iNew">
    <p><input type="radio" id="radioCat" name="group1" value="category"> <span id="checkCat">Category</span>
     <input type="radio" id="radioSubA" name="group1" value="subA" checked="checked"> <span id="checkSubA">subA</span></p>
    </form>
    </body></html>

  6. #6
    Unobtrusively zen silver trophybronze trophy
    paul_wilkins's Avatar
    Join Date
    Jan 2007
    Location
    Christchurch, New Zealand
    Posts
    14,527
    Mentioned
    84 Post(s)
    Tagged
    4 Thread(s)
    The first of the two function needs to be instantiated, which in my example is the (i) part at the end of the function.
    Programming Group Advisor
    Reference: JavaScript, Quirksmode Validate: HTML Validation, JSLint
    Car is to Carpet as Java is to JavaScript


Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •