2
votes

I'm playing around with meteor's Todos example to learn how it works and I'm trying to add a Description to Todo items that appears below the title when you click on it. The "when you click on it" part is what I'm having trouble with. I'm trying to figure out how to add a boolean "viewing" variable to each Todo item client-side without having any reflection of that serverside. Obviously when 1 user is viewing an item not every user would want to view that items. I got a basic implementation going by adding a client-only Collection that was just a list of Todo ids that were being viewed and then used this code for the template to know if a thought was being viewed:

Template.todo_item.viewing = function () {
    return Viewing_Todos.find({title: this.title}).count() > 0;
};

This isn't really an ideal solution though. As I said I'd like a client-side boolean variable on each todo item to say whether or not it's being viewed.

I tried changing it to this:

Template.todo_item.viewing = false;

and then my on click event was:

'click .todo-description': function(event) {
   event.target.viewing = !event.target.viewing;
}

I added in console log output to see what "event.target.viewing" was and it seemed to be updating correctly but Handlebars was no longer dynamically updating the DOM to reflect that the item was in a "viewing" state.

The Handlebars HTML is:

      {{#if viewing}}<br/>
      <div class="todo-description">
          {{text}}
      </div>
      {{/if}}

I thought I might have to do it in a helper so I tried the following:

Template.todo_item.helpers({
    viewing: false;
});

but that doesn't seem to work at all either.

Thanks for the help! I'm pretty new to web development in general but I'm loving Meteor so far.

2

2 Answers

1
votes

Having that separate client-side database is entirely un-needed for this. In general, if you want to control UI state, and "viewing" is a perfect example, you can set a Meteor Session variable. The code might look like this:

// Click event
'click .todo-description': function (event, templ) {
    Session.set('viewing-todo', templ._id); // We're now viewing todo with id=_id
}

// Are they viewing a todo?
if (Session.get('viewing-todo')) // ...

// Or perhaps they're viewing "foobla" todo?
if (Session.equals('viewing-todo', 'fooblaId')) // ...

However, if you want to have a separate "viewing" flag for every single todo item (would they be able to view more than one at a time?), you could try attaching a data-* attribute to each todo element. This is simple to do with the jQuery data method. Your code might look like this:

// Click event
'click .todo-description': function (event, templ) {
    $(event.target).data('viewing', true);
}

// Are they viewing a todo?
if ($('#todoElement').data('viewing')) //...
1
votes

You should use Session variables like this :

Template.todo_item.created=function(){
    Session.set(this.data._id+"-viewing",false);
};

Template.todo_item.helpers({
    viewing:function(){
        return Session.get(this._id+"-viewing");
    }
});

Template.todo_item.events({
    "click .todo-description":function(event,template){
        var viewing=Session.get("-viewing");
        Session.set(template.data._id+"-viewing",!viewing);
    }
});

This code assumes that the todo_item template data context is a valid Todos document with its own unique _id.

We use this _id to name a unique session variable that will reactively store the current viewing state of the item, the template will rerender whenever this variable is modified.

Notice how we access the data context differently :

  • In created/rendered/destroyed callbacks, "this" is bound to the template instance, and we can access the data context using the data property (this.data).

  • In template helpers, "this" is bound to the data context directly.

  • In events handlers, the template instance is accessible via a parameter so we can once again use the data property (template.data._id).

In a future version of Meteor, templates will have their own scoped Session variables and hopefully this technique will be a lot easier to implement.