Can Meteor live changes have animations? - meteor

How does Meteor handle live changes? For instance I don't want changes to be instantaneous, but with some kind of animation of sorts. If we place the items being changed using css animations/transitions does this work? What about jQuery animations for older browsers?

Here is a working example of a simple animation with meteor.
The situation here is that we have a list of items. If the user clicks on any of those items the item will animate 20px to the left.
JS
//myItem
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"
});
}
};
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; }
Instead of using fancy CSS you can also animate with jQuery:
Template.myItem.rendered = function(){
if(Session.get("selected_item") === this.data._id){
$(this.firstNode).animate({
left: "-20px"
}, 300);
}
};
But then you need to remove the CSS code.
.myItem { transition: all 200ms 0ms ease-in; }
.selected { left: -20px; }

There is a workaround like this:
<template name="foo">
..content..
{{bar}}
</template>
In this case Meteor will call Template.foo.bar everytime this template gets rendered. So within this function you can do all kinds of Jquery or CSS3 animations (for example by adding a class to the templates div).

For CSS transitions, there are two options you can go with:
1. Reactively: the Meteor way
2. Directly: the jQuery way
Here is a working example:
http://bindle.me/blog/index.php/658/animations-in-meteor-state-of-the-game

Related

Programmatically style an input element's "focus" pseudo-class with Vue

So far I'm using event listeners to set the :focus pseudo-class of an input element:
const element = document.getElementById("myElementID");
element.addEventListener("focus", (e) => {
e.target.style.borderColor = "red";
});
element.addEventListener("blur", (e) => {
e.target.style.borderColor = "";
});
JSFiddle
Although this works, is there a more elegant or idiomatic way to achieve the same thing with Vue?
You don't have to listen to native events using vanilla JS syntax and getElementById when using Vue. You can specify the v-on-handler directly on the element in the template, like so:
// Vue SFC
<template>
<div>
<input #blur="doSomething" #focus="doSomethingElse" />
</div>
</template>
<script>
export default {
methods: {
// Both methods receive the same native dom event as a vanilla listener would
doSomething(e) {
e.target.style.borderColor = "red";
},
doSomethingElse(e) {
e.target.style.borderColor = "";
}
}
}
</script>
If you only want to apply this simple styling then a pure CSS solution, as provided by Manas Khandelwal, is sufficient and preferrable.
You can simply do this with CSS. Like this:
input {
outline: none;
}
input:focus {
border-color: red;
}
<input type="text" id="myElementID" />

Pause/play ALL the CSS animations of every child element

I'm creating a dashboard page which is full of CSS animations. From Bootstrap stuff (animated progress bars) to custom animations.
When you click some of the elements, a near full-screen modal is triggered, which overlaps all the animations, so I want to temporarily pause them all (because of possible performance issues) by adding/removing a class to one of the top elements, and using CSS to pause all animations when that class is set.
This solution would use only a single line of js, just to toggle the class on opening the modal.
My template looks somewhat like this:
<body>
<div class="modal">
<!-- Modal code -->
</div>
<div class="app">
<!-- Template -->
</div>
</div>
Is it possible to add a class to .app which pauses every CSS animation in every child element?
Note 1:
I know you can use the exact opposite of what I request: namely, have a default .animation-play class to one of the top elements, and prefix every child element with an animation with this class, and then remove this class to pause every animation. Just like:
app.animation-play .somediv .somediv .element {
// animation code
}
app.animation-play .somediv .element {
// animation code
}
app.animation-play .somediv .somediv .somediv .somediv .element {
// animation code
}
But then I have to edit a lot of CSS code, and it doesn't look very nice either.
Note 2:
I'm also open for a JS solution, but I would heavily prefer a pure CSS way of achieving this.
You can use a universal selector to target everything when a class of 'paused' is added to your app wrapper, however many CSS linters still warn against using these due to performance impacts.
To be honest the impact is probably minimal these days and many CSS resets for example use them.
You could use something like:
.app.paused * {
animation: none;
}
EDIT:
Looking through the comments above it seems as though the above selector doesn't have enough precedence to overwrite the animations so '!important' has been added.
.app.paused * {
animation: none !important;
transition: none !important;
}
However this is generally not a great idea, I always try to avoid using '!important' at all costs due to the difficulty in maintaining the stylesheet with these selectors in place. If you can overwrite the animations with a greater precedence then it would be better to do so rather than using '!important'.
EDIT 2:
As you mentioned you were open to JS solutions, here is some JS that should clear all the animations within a given selector. I'm not sure what the performance impact of doing it this way is but I added it here just in case someone else prefers to do it only using JS:
let stopAnimationsWrap = document.querySelector('.app');
let stoppedAnims = [];
// Stop animations
document.querySelector('.stop').addEventListener('click', () => {
let appAllEls = stopAnimationsWrap.querySelectorAll('*');
let allElsAr = Array.prototype.slice.call(appAllEls);
allElsAr.forEach((thisEl) => {
let elClass = thisEl.classList[0];
let cs = getComputedStyle(thisEl, null);
let thisAnimation = cs.getPropertyValue('animation-name');
if (thisAnimation !== 'none') {
stoppedAnims.push([elClass, {
'animationName': thisAnimation
}]);
thisEl.style.animationName = 'none';
}
});
});
// Start animations
document.querySelector('.start').addEventListener('click', () => {
stoppedAnims.forEach((thisEl) => {
let domEl = '.' + thisEl[0];
stopAnimationsWrap.querySelector(domEl).style.animationName = thisEl[1].animationName;
});
});
Fiddle:
https://jsfiddle.net/vu6javb2/14/
.app {
-webkit-animation-play-state: paused; /* Safari 4.0 - 8.0 */
animation-play-state: paused;
}
on hover:
.app:hover {
-webkit-animation-play-state: paused; /* Safari 4.0 - 8.0 */
animation-play-state: paused;
}

Why Does Turn.js Only Work Once in Meteor Application?

I want to integrate Turn.js in a meteor project, but come across a "small" problem ,
the script work well the first time I "load" the template , but wouldn't work when i come across the same template.
{{#if correspondances_readingMode}}
<script >
function loadApp() {
// Create the flipbook
$('.flipbook').turn({
// Width
width:922,
// Height
height:600,
// Elevation
elevation: 50,
// Enable gradients
gradients: true,
// Auto center this flipbook
autoCenter: true
});
}
// Load the HTML4 version if there's not CSS transform
yepnope({
test : Modernizr.csstransforms,
yep: ['../../lib/turn.js'],
nope: ['../../lib/turn.html4.min.js'],
both: ['css/basic.css'],
complete: loadApp
});
</script>
<style>
.page{
width:400px;
height:300px;
background-color:white;
line-height:300px;
font-size:20px;
text-align:center;
}
</style>
<div class="flipbook">
{{#each myPost}}
<div class="page">
{{{text}}}
</div>
{{/each}}
</div>
{{/if}}
All seems to go as if the script was only executed when the user come across the template the first time , but wouldn't launch again the second time.
I have try many thing, but I came to think it's because of the handlebar {{#if}}
P.s :
On chrome the second time it's loaded it doesn't show turn.js as a script :
I was running into the same problem. I figured that the width of the booklet was calculated before the containing div got its full width. I set a delay of 1 second after rendering and now it seems to work fine.
Template.menu.rendered = function(){
setTimeout(function() {
import '/imports/turn.min.js';
$(window).ready(function() {
$('#magazine').turn({
display: 'double',
acceleration: true,
gradients: !$.isTouch,
elevation:50,
when: {
turned: function(e, page) {
// console.log('Current view: ', $(this).turn('view'));
}
}
});
});
$(window).bind('keydown', function(e){
if (e.keyCode==37)
$('#magazine').turn('previous');
else if (e.keyCode==39)
$('#magazine').turn('next');
});
}, 1000);
};
`

Animating div content populated by AngularJS without jQuery

I have a div like this:
<div class="row">
<alert ng-repeat="alert in alerts" type="alert.type" close="closeAlert($index)">{{alert.msg}}</alert>
</div>
I create the alerts in angularjs (and I'm using bootstrap), and while this works great, the visual effect is kind of uncool. As alerts are added to the div, all page content is shoved ungracefully down to make room for the new alert.
I would like to animate the movement so that it is at least smooth. But I don't want to use jQuery. I've played with the CSS3 transitions, but can't seem to get them to work smoothly.
Can I do this where the trigger is a change in div height? How?
you can do it with directives in their link function. i think you wont mind about so small piece on jquery code
myModule.directive('animateRight', function () {
var linker = function (scope, element, attrs) {
var right = function() {
$(this).animate({
{"height": "800px"},
"fast");
})
}
element.on('click', right);
};
return {
restrict:'A',
link:linker
}
})
<div animate-right class="box"></div>
Ok, so I don't like to answer my own question, but this seems like the way to do it...
I used AngularJS 1.2, along with the new ngAnimate module. You need to add angular-animate.js, and reference the animate module, so at the end here's what my modules looked like:
var app = angular.module('tracker', ['$strap.directives', 'ui.bootstrap', 'ngRoute', 'ngAnimate']);
After that, its super simple, and very much CSS3 animations. My alert line ended up with a class repeat-item:
<alert class="repeat-item" type="alert.type" data-ng-repeat="alert in alerts" close="closeAlert($index)">{{alert.msg}}</alert>
And I added some CSS to target that class with the angularjs triggers:
.repeat-item.ng-enter,
.repeat-item.ng-leave {
-webkit-transition: 0.2s linear all;
-moz-transition: 0.2s linear all;
-o-transition: 0.2s linear all;
transition: 0.2s linear all;
}
.repeat-item.ng-enter,
.repeat-item.ng-leave.ng-leave-active {
opacity: 0;
}
.repeat-item.ng-leave,
.repeat-item.ng-enter.ng-enter-active {
opacity: 1;
}
And voila a nice fade in and out animation.
This page really explains very well how to do it. Cheers to Michael Benford for the great link.

Meteor transition effects for auto-updating content

Looking at the meteor leaderboard example, I understand how content in the view templates is bound to functions in the javascript application file. For example, consider this snippet from the view file which defines the "selected" class to determine which name is highlighted yellow:
<template name="player">
<div class="player {{selected}}">
<span class="name">{{name}}</span>
<span class="score">{{score}}</span>
</div>
</template>
The value of {{selected}} is defined and kept up to date in this function from leaderboard.js:
Template.player.selected = function () {
return Session.equals("selected_player", this._id) ? "selected" : '';
};
My question is: How would you add transition effects to this auto updating process? For example, say we wanted the yellow highlighting to fade to white on the existing name, and then fade into yellow on the new name, whenever a new name was clicked. How could we accomplish that in meteor?
The easiest way would be using CSS transitions. Just ensure that the element is preserved (so it isn't replaced on re-draw, just patched):
Template.player.preserve(['.player']);
Then go nuts with the CSS transitions:
.player {
background-color: white;
transition: background-color 500ms linear 0;
-moz-transition: background-color 500ms linear 0;
// etc
}
.player.selected {
background-color: yellow;
}

Resources