SitePoint Sponsor

User Tag List

Results 1 to 8 of 8
  1. #1
    SitePoint Member
    Join Date
    Feb 2007
    Posts
    19
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    Javascript object problems

    Hi all,

    Just a quick javascript question. I have been playing with objects in JS with some success, but have come accross a bit of a problem, which I cant quite get my head around.

    I have a project in which multiple forms are used, so i created a class which would carry out the repetetive processes I was going through for each form. In use, the object is first created, then init is called to add the appropriate event listeners and carry out the required tasks etc. the code is below

    Code:
    function formHandler(form, url)
    {
        //form object
        this.form = form;
        this.url = url;
        
        /*
        * Function to initialise the form
        */
        this.init = function() {
                
            //Add the highlightors
            this.addHighlightor(this.form.getElementsByTagName("input"));
            this.addHighlightor(this.form.getElementsByTagName("select"));
            this.addHighlightor(this.form.getElementsByTagName("textarea"));
            
            //Give focus to the form
            Form.focusFirstElement(form);
            
            //Add the onsubmit handler
            form.onsubmit = this.validate;
            
                    
        }
        
        
        /*
         * Function takes an array of objects and adds a highlightor event to their parent nodes
        */
        this.addHighlightor = function(elems) {
            for (var i = 0 ; i < elems.length ; i++) {
              elems[i].onfocus=function(){
                if (this.parentNode.className != "submit")
                    this.parentNode.className+=" active";
              };
              elems[i].onblur=function(){
                if (this.parentNode.className != "submit") {
                    //Get original class name
                    var name = this.parentNode.className.split(" ");
                    if (name[1] == undefined) {
                        this.parentNode.className=name[1];
                    } else {
                        this.parentNode.className="";
                    }
                }
              };
            }
        }
        
        this.test = function() {
            alert('test');    
        }
        
        this.test2 = function() {
            alert('called');
            this.test();    
        }
        
        /*
         * Function validates the inputs within the form if there is a class name of required
         * @return
        */
        this.validate = function() {
            
            //Use prototype to obtain all the elements in the form
            var elements = Form.getElements(form.id);
            
            
            for (var i = 0 ; i < elements.length ; i++) {
                if(elements[i].className.indexOf('required') != -1) {
                    if (!Field.present(elements[i])) {
                        
                        //find the label
                        for(var y=0 ; y < elements[i].parentNode.childNodes.length ; y++) {
                            if (elements[i].parentNode.childNodes[y].tagName == "LABEL") {
                                var desc = elements[i].parentNode.childNodes[y].innerHTML;
                            }
                        }
                        
                        alert(desc+" must be entered");
                        elements[i].style.backgroundColor = "#FFC7D4";
                        elements[i].focus();
                        return false;    
                    }
                }
            }
            this.test2();
        }
    }
    The problem I am having is with the onsubmit event listener for the form. The vaidate function is performed onsubmit, but when it reaches this.test2() it tells me it isnt a function and dies.

    After ruling out typos etc I think this is something more fundamental that I am not understanding so any help would be greatly appreciated!

    Many many thanks

    /Matt

  2. #2
    SitePoint Wizard
    Join Date
    Mar 2001
    Posts
    3,537
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    The 'this' keyword refers to an object. However, what object that is depends on when 'this' is evaluated. Inside a constructor function, 'this' refers to the object being constructed, e.g.

    this.propName = 10;

    When the constructor function executes, 'this' has to be evaluated immediately, and js determines that 'this' refers to the current object being constructed.

    On the other hand, when you define an event handler function, you are saying, "Please execute this function at some time in the future". Therefore, the code inside the function is not executed immediately, and 'this' doesn't refer to any object yet. Eventually, the function will execute and 'this' will have to be evaluated. However, when the event handler function does execute, it will be long after the constructor function has finished executing. When js finally executes the event handler function, js will evaluate 'this' and js will determine that the current object is the html element upon which the event is occurring.

    There are several ways to get around the problem of 'this' referring to different objects at different times. One way is to create a variable in the constructor function and assign 'this' to it:

    var someName = this;

    That statement will have to be evaluated immediately when the constructor function executes, and someName will be assigned a reference to the current 'this", which is the object being constructed. Unlike 'this', a variable you create will not change what it refers to later. So someName can be used instead of 'this' inside the event handler function to refer to the original object that was created.

  3. #3
    SitePoint Member
    Join Date
    Feb 2007
    Posts
    19
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Hi 7stud,

    Thanks a lot for your reply, I think I get what you mean, though I would of never worked that out for myself!

    So by adding a reference to 'this' (i.e. the object in its initialised state) into the constructor then the reference to this 'this' within the onevent function would refer to the actual initialised object. Sudo code below;

    Code:
    function MyClass(form, url) {
    
    this.form = form;
    this.url = url;
    
    init = function() {
          this.someName = this;
    
          form.onsubmit = this.eventHandler;
    }
    
    test = function() {
         alert('test');
    }
    
    eventHandler = function() {
         //some code here
    
         //Instead of using this.test() use the reference to the object?
         someName.test(); 
    }
    
    }
    Hopefully that is what you were meaning. I'm currently at work so will have to wait untill this evening to try it out, but I will let you know how im getting on.

    Once again, thanks very much for the reply its been a massive help!

    /Matt

  4. #4
    SitePoint Wizard
    Join Date
    Mar 2001
    Posts
    3,537
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    So by adding a reference to 'this' (i.e. the object in its initialised state) into the constructor then the reference to this 'this' within the onevent function would refer to the actual initialised object.
    The value of 'this' will be determined by js when the code containing 'this' is executed. Depending on when the code containing 'this' is executed, js will give 'this' a different value. You cannot alter the value of 'this'--js determines its value. No matter what you would like the value of 'this' to be, js doesn't care--whatever js determines is the correct value for 'this' is what the value will be.

    On the other hand, if you assign a value to a variable that you create, the value of that variable will never change--unless you explicitly change it. For instance if you write:
    Code:
    var specialJsVar = 10;
    var myVar = specialJsVar;
    
    specialJsVar = 20;
    the value in myVar does not change even though the value of specialJsVar changed. 'this' operates like specialJsVar and js is the one changing the value of specialJsVar from 10 to 20.

    Therefore, you can create a variable and assign 'this' to it:

    var someName = this;

    When that code executes, js will grab the current value for 'this' and store it in the variable someName. If the value of 'this' later changes, that will not affect the value stored in someName.

    As a result, if you want to save the value currently stored in 'this', you can assign 'this' to a variable that you create. Then inside your function you can use the name of the variable instead of 'this'.
    Last edited by 7stud; Feb 5, 2007 at 14:48.

  5. #5
    SitePoint Member
    Join Date
    Feb 2007
    Posts
    19
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Hi 7stud,

    Once again, thanks a lot for your help. I have implemented this and the code is now executing without a problem, so thanks for that.

    I think I understand, but what im not quite sure about is what exactly 'this' was evaluation to when it was being called as the event handler. Also, I am going about what im doing in a stupid way?

    I have now ammended the code to read as below;

    Code:
    function formHandler(form, url)
    {
    	//form object
    	this.form = form;
    	this.url = url;
    	var  instance = this;
    So should i be setting form, and url to 'var' as opposed to 'this' as well?

    My second question is, when i use this class I use the code as below;

    Code:
    	form = new formHandler(formObj, 'theUrl');
    	form.init();
    init then calls certain contained methods, and adds the relevent event listeners etc. if, after form.init(); I then add
    Code:
    formObj.onsubmit = form.validate;
    I dont understand how 'this' could be something different, as the function is being called from the instance of the formHandler class.

    Would you go about it in this way or am I missing the idea here?

    I really appreciate your help on this, I have allready learned a whole bunch from your comments before, so if (as im sure you are!) your getting sick of answering my questions then if there are any links that you think cover this I would happily go immerse myself in that for a little time!

    Many many thanks

    /Matt

  6. #6
    SitePoint Member
    Join Date
    Feb 2007
    Posts
    19
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Hello once again (and sorry for double posting)

    After reading this article I now understand where I was going wrong. So many many thanks for all your advice, Im pretty sure i would of never figured that out, so your help has been invaluable.

    Just for any others reading this page as 7stud informed me the this had a different connotation in the scope of being used as an event handler function.

    In essence (again as 7stud pointed out) in the scope ofbeing initialised 'this' refers to the parent object, in the scop of the event handler, 'this' refered to the object that called(fired) the even, so it refered to the html form object, and not the instance of the object it was held in.

    Massive thanks to 7Stud for your patience with this, i really appreciate it!

    /Matt

  7. #7
    SitePoint Wizard
    Join Date
    Mar 2001
    Posts
    3,537
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    After reading this article I now understand where I was going wrong.
    ppk's site is a wealth of js information and cross browser anomalies, so keep it bookmarked.

  8. #8
    SitePoint Enthusiast
    Join Date
    May 2007
    Posts
    33
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Thanks 7stud and mwells, that made my day! I had exactly the same problem as mwells, even using initializer functions and classes in exactly the same way. Have been searching for quite some time for a solution. But here I find a clear problem and answer description I love it!


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
  •