I am trying to implement an animation where an item animates to the left after it gets selected. The following code works. But only about 80% of the time.
JS
//myItem
Template.myItem.rendered = function(){
if(Session.get("selected_item") === this.data._id){
$(this.firstNode).addClass("selected");
} else {
$(this.firstNode).removeClass("selected");
}
};
Template.myItem.events({
"click .myItem": function(evt, template){
Session.set("selected_item", this._id);
}
});
//myItemList
Template.myItemList.helpers({
items: function(){
return Items.find();
}
});
Templates
<template name="myItem">
<div class="myItem">{{name}}</div>
</template>
<template name="myItemList">
{{#each items}}
{{> myItem}}
{{/each}}
</template>
CSS
.myItem { transition: all 200ms 0ms ease-in; }
.selected { left: -20px; }
I also tried to wrap the code into a Meteor.defer()
to make sure that really everything is ready to do the animation.
Template.myItem.rendered = function(){
Meteor.defer(function() {
if(Session.get("selected_item") === this.data._id){
$(this.firstNode).addClass("selected");
} else {
$(this.firstNode).removeClass("selected");
}
});
};
But that results in this kind of error:
Exception from defer callback: TypeError {}
It would be great to see any ideas how to make the animation work every time.
UPDATE
Krab got the right answer. The exception was coming from the this
reference. I want to add some details. So here are two working versions on how to do the animation:
with Meteor.defer()
Template.myItem.rendered = function(){
var instance = this;
if(Session.get("selected_item") === this.data._id){
Meteor.defer(function() {
$(instance.firstNode).addClass("selected"); //use "instance" instead of "this"
});
}
};
(We don't actually need the else block here because meteor will remove the selected
class if it redraws the item.)
or with $().animate()
Template.myItem.rendered = function(){
if(Session.get("selected_item") === this.data._id){
$(this.firstNode).animate({
left: "-20px"
}, 300);
}
};
If you use the jQuery approach you need to remove the CSS code.
.myItem { transition: all 200ms 0ms ease-in; }
.selected { left: -20px; }
try this, because this
pointer in defer callback isn't the same as if the code is executed directly in rendered callback
Template.myItem.rendered = function(){
var self = this;
Meteor.defer(function() {
if(Session.get("selected_item") === self.data._id){
$(self.firstNode).addClass("selected");
} else {
$(self.firstNode).removeClass("selected");
}
});
};
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