1

Domain model

var Question = function(text, answerType){
    this.id = 0
    this.text = text;
}

var Form = function(){
    this.questions = [] 
    this.addQuestion = function(question){
        question.id = this.questions.length + 1
        this.questions.push(question)
    }
}

Renders a Form

var FormRenderer = function(){
    this.wrapperSelector = "#wrapper"
    this.render = function(form){
       // how to access renderQuestion member of FormRenderer within the higher-order function?
       $(form.questions).each( function(){ **this.renderQuestion(form, this) }**) 
    }

    this.renderQuestion = function(form, question){
        var questionDomId = "question" + question.id

        var questionText = '<input type="text" size="75" name="questionText" value="'+ question.text +'" /><br/><br/><br/>'
        var questionWrapper  = "<div id='" + questionDomId + "'>" + questionText + "</div>"

        // how do i access wrapperSelector member of FormRender when renderQuestion is called as higher-order function?
        **$(this.wrapperSelector).append(questionWrapper)** 
    }
}

Client code

var q1= new Question("question1", "Text Box")
var form = new Form()
form.addQuestion(q1)

var formRenderer = new FormRenderer()
formRenderer.render(form)

The question is the same as the title. I have asked help for a specific example above with Javascript comments. Any help is appreciated.

1
  • Please note that each is the higher-order-function, not renderQuestion. Btw, this looks to me like inappropriate usage of each - just use a for-loop and you don't have those problems. Commented Oct 20, 2012 at 12:15

4 Answers 4

1

You need to store a reference to the object like so:

var FormRenderer = function(){
    this.wrapperSelector = "#wrapper"
    this.render = function(form){
       $(form.questions).each( this.renderQuestion) ;
    }

   var self = this; // <--------------- 

   this.renderQuestion = function(form, question){
        var questionDomId = "question" + question.id

        var questionText = '<input type="text" size="75" name="questionText" value="'+ question.text +'" /><br/><br/><br/>'
        var questionWrapper  = "<div id='" + questionDomId + "'>" + questionText + "</div>"

        // now use self instead of this
        $(self.wrapperSelector).append(questionWrapper);
    }
}
Sign up to request clarification or add additional context in comments.

1 Comment

In your case, the form parameter is the array index.
0

You can get the parent object instance in this inside the member functions, by calling them like below.

if object is your instance, and func is a member function inside which you want this to be your instance itself, then you can call the member function as:

obj.func.call(obj, <params>);

instead of

object.func(<params>);

In your case, this would be:

var fR = new FormRenderer(<params>);
...
fR.renderQuestion.call(fR, <params>);

Your renderQuestion can use this just like outside. i.e.

var FormRenderer = function(){
    this.wrapperSelector = "#wrapper"
    ...
    this.renderQuestion = function(form, question){

        // this refers to the object itself, so you can call        
        $(this.wrapperSelector).append(...);
    }
}

1 Comment

fR.renderQuestion.call(fR, <params>); would be absolutely equal to fR.renderQuestion(<params>);. However, that was not the question - the OP's problem is that this does not point to the instance when the method is fed into jQuery.each
0

Had to restructure a little to solve the problem based on input from Pumbaa80 and Bergi. Thanks for your answers.

var FormRenderer = function(){
    this.render = function(form){
        var formEventHandler = new FormEventHandler(form)
        $(form.questions).each(new RenderQuestion(formEventHandler).render)
    }

    RenderQuestion = function(formEventHandler){
        this.formEventHandler = formEventHandler
        this.wrapperSelector = "#wrapper"
        var self = this
        this.render = function(index, question){
            var questionDomId = "question" + question.id

            // generate elements
            var questionText = '<input type="text" size="75" name="questionText" value="'+ question.text +'" /><br/>'
            var questionWrapper  = "<div id='" + questionDomId + "'>" + questionText + "</div>"

            // append to dom
            $(self.wrapperSelector).append(questionWrapper)
        }
    }
}

1 Comment

Instantiating a new instance of the local RenderQuestion each time render is called seems useless. Why don't you just pass a function which does those things?
0

Don't use jQuery.each - it changes the this reference to something unusual. You could use ES 5.1 bind and the normal forEach like this:

FormRenderer.prototype.render = function(form) {
    form.questions.forEach(this.renderQuestion.bind(this, form));
};

I'd recommend to use a classical for-loop, which is much easier to read and faster than any higher-order-things:

FormRenderer.prototype.render = function(form) {
    for (var i=0; i<form.questions.length; i++)
        this.renderQuestion(form, form.questions[i]);
};

If you really wanted/needed to use jQuery.each, you'd need to preserve the reference to the current FormRenderer instance (this) in a variable:

FormRenderer.prototype.render = function(form) {
    var renderer = this;
    $.each(form.questions, function(i) {
        renderer.renderQuestion(form, this);
    });
};

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.