Reputation: 2471
I have a button in the HTML of my template. How can I make it call a function on the object that is rendered at that time?
I realize this
is refering to the button at that moment. But how do I refer to the person?
TEMPLATE
<script type="text/template" id="tpl-person">
<tr>
//...
<td><button onclick="this.happyBirthday()">Birthday</button></td>
</tr>
</script>
JAVASCRIPT
var Person = function(name, age){
//....
this.happyBirthday = function(){
this.age ++;
}
this.render = function(){
var template = _.template($("#tpl-person").html());
$("#peopleWrapper").append(template(this));
}
//constructor
this.name = name;
this.age = age;
this.render();
}
Upvotes: 0
Views: 3223
Reputation: 437376
It is not possible to do this because attaching the event handler from HTML requires that the handler function be serialized (i.e. in source form). There is no real way to serialize a function in JavaScript, and even if you could there is another showstopper: inside the function this
to be a reference to an existing JavaScript object which is impossible because again, everything that you do needs to be serialized.
An easy workaround would be to attach the event handler with jQuery at the time the template is rendered.
Taking into consideration the desired value of this
, you can define your event handler function from within any Person
method as
// $.proxy because otherwise "this" would be the clicked button element
$.proxy(this.happyBirthday, this);
Attaching the click handler is straightforward:
var clickHandler = $.proxy(this.happyBirthday, this);
var html = $(template(this));
$("#peopleWrapper").append(html.find("button").click(clickHandler).end());
That said, this does not look like a good way to arrange things. Consider a different suggestion: attach the Person
object to the rendered template (e.g. through jQuery's .data
) and refer to it from within the click handler; the handler itself can be delegated to save on functions and allow dynamically adding more rendered templates.
For example:
The HTML template itself does not attach any handlers at all.
When adding the rendered template use .data
to associate it with the person object and do something to mark it as person-associated visible from a DOM perspective. This could be as simple as adding a data-person
attribute (or a CSS class):
$("#peopleWrapper").append(
$(template(this)).data("Person", this).attr("data-person", ""));
Attach a delegated handler to the DOM that recognizes clicks on the buttons and, starting from the clicked element, finds the associated person object and calls the happyBirthday
method:
$("#peopleWrapper").on("click", "[data-person] button", function() {
$(this).closest("[data-person]").data("Person").happyBirthday();
});
Upvotes: 2