I am trying to implement a hierarchy of expandable post comments like in e.g. Quora, so that the user can click a comment and see any replies.
To this end, I would like to keep track of whether each "comment" template instance is "expanded" or not, toggling the state in the event handler.
I could do this using a whole stack Session variables (i.e. one for each comment), but this seems clumsy since there are an arbitrary number of comments on any given page.
Below is a snippet of what I'm trying at the moment.
JS:
Template.comment_item.events = {
'click #comment-content': function( e, instance ) {
this.expanded = true; // also tried instance.data.expanded = true
}
};
Template.comment_item.helpers({
showChildComments: function(){
this.expanded;
}
});
HTML:
<template name="comment_item">
<li class="comment comment-displayed" id="{{_id}}">
<div class="comment-body">
<div id="comment-content">
<!-- some comment data here -->
</div>
{{#if showChildComments}}
<ul class="comment-children comment-list">
{{#each child_comments}}
{{> comment_item}}
{{/each}}
</ul>
{{/if}}
</div>
</li>
</template>
Unfortunately, when I step through, it seems that in the showChildComments helper, the template instance can't see the expanded variable. I did notice in the docs it says instance.data is read only in the events map.
Is there any way to modify the template instance within the event map directly?
You can create properties for a template instance inside of it's created event handler. And you can access the template instance as the second argument of the event map function.
Template.comment_item.created = function() {
this.showChildren = false;
};
Template.comment_item.events({
'click .comment-content': function(event, template) {
template.showChildren = true;
}
});
HOWEVER:
What I would suggest that you do instead is simplify your template to this:
<template name="comment_item">
<li class="comment comment-displayed" id="{{_id}}">
<div class="comment-body">
<div class="comment-content"> <!-- changed this to a class -->
<!-- some comment data here -->
</div>
</div>
</li>
</template>
And then programmatically add the child comments to the comment-body in your event-handler. Keep in mind the following from the Meteor documentation:
A template that you declare as
<template name="foo"> ... </template>
can be accessed as the function Template.foo, which returns a string of HTML when called.
Oh, and you pass context to a template function as a JSON object. E.g.:
var context = {_id: comment_id, text: "Comment text!"};
Template.comment_item(context);
Meteor now gives you access to template instances from within a helper, using Template.instance()
. In fact, it's a great way to increase the reusability of your template.
The example source below is from this article, authored by David Burles of Percolate Studio.
Template.hello.created = function () {
// counter starts at 0
this.state = new ReactiveDict();
this.state.set('counter', 0);
};
Template.hello.helpers({
counter: function () {
return Template.instance().state.get('counter');
}
});
Template.hello.events({
'click button': function (event, template) {
// increment the counter when button is clicked
template.state.set('counter', template.state.get('counter') + 1);
}
});
The article does a great job of illustrating why you would want this approach.
The advantage of storing information in the template instance is that you can make templates increasingly modular and decreasingly dependent on the place they are used.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With