Meteor transition effects for auto-updating content - meteor

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;
}

Related

How to custom transition for each component?

I have 3 components which I want to show a transition effect when they enter/leave.
There's 1 "main" component and the 2 others show up when you press the associated button. My current sample code is here: https://jsfiddle.net/5aq1k05L/
<transition :name="'step_' + currentView" mode="out-in">
<component :is="currentView"></component>
</transition>
CSS:
.step_componentA-enter-active {
transition: transform 0.4s;
}
.step_componentA-leave-active {
transition: transform 0s;
}
.step_componentA-enter {
transform: translateX(-100%);
}
.step_mainComponent-leave-active {
transition: transform 0.3s;
}
.step_mainComponent-leave-to {
transform: translateX(-100%);
}
.step_componentB-enter-active {
transition: transform 0.4s;
}
.step_componentB-leave-active {
transition: transform 0s;
}
.step_componentB-enter {
transform: translateX(100%);
}
What I am trying to do:
When I click on the "componentA" button, I want that component to slide from the left while "mainComponent" is still visible in the background (not stripped out of elements like now) during the transition.
Same thing for "componentB", except it will slide from the right, and will back to the right when clicking back.
What am I missing? https://jsfiddle.net/5aq1k05L/
Edit 2:
Here a working example with the componentA and componentB that are sliding over the mainComponent -> https://jsfiddle.net/5aq1k05L/8/
I changed the transition to mode:in-out, I added a z-index for each component, and put the components in position:absolute and the app in position:relative
Edit:
Here a working example for your case -> https://jsfiddle.net/5aq1k05L/4/
When you analyse the script step by step, you see that the class when the componentB is leaving is step_mainComponent-leave-active step_mainComponent-leave-to that it makes a classic toggle relative to the mainComponent style.
If you want to use different animations, you should use enter-active-class and leave-active-class etc (see more here) - or put two vars in name, i guess, with a dynamic value relative to the previous view, in the store like currentView is.
It could be like this :
<transition
:name="'step_' + currentView + '_from_' + prevView"
mode="out-in"
>
In the store (you ll need to update the states, mapState, etc.. as well too) :
SET_CURRENT_VIEW(state, new_currentView) {
state.prevView = state.currentView;
state.currentView = new_currentView;
}
Hope it ll help you

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;
}

Restate(override) css-transition after it has already triggered

Is it possible to restate(override) css-transition after it has already triggered?
It seems down right impossible to override transition-delay after the css-transition has already taking effect.
(Especially considering the possible case when delay duration might have past already, delay value gets shortened and so on.)
However I failed to find concrete explanation.
I suppose css-transition has to be instructed at before or the exact same time when the change of target property (background-color in this case) is instructed?
(Sorry I had to edit numerous times to narrow down my question. If anyone wonder why I need such thing, I explained a mechanism I want below. It's already in simplified of my project.)
What I'm trying to do is
Before jQuery 'load' event, background-color: transparent is applied.
Then on jQuery 'load' event, apply background-color: red
(which is determined by css with class name loaded added by jQuery).
On the otherhand, transition-delay is determined separately by its class name which is provided by jQuery.
Clarification
Just to differentiate from other similar questions..
I only need transition-delay to be override conditionally.
Although interestingly, it would succeed when background-color is changed alongside.
Overriding happens conditionally, i.e: CSSOM remains constant but DOM's class name might change after its initial state. (To be specific to this case, class is added when the button is pressed.)
Override succeeds while DOM stays constant, but that's not what I want.
Here's fiddle to illustrate the situation
HTML
<div>
<!-- class name "loaded" will be given after load event. -->
<p class="delay delay-1s">
<!-- class name 'delay-1s' will be replaced with 'delay-5s' with button -->
This will be turning into red after loaded in..<br>
1.) 1 seconds without button or<br>
2.) 5 second with button
</p>
</div>
<button id="change-delay">Change delay to 5s</button>
CSS
/* Make P from transparent to red when loaded */
div p {
background-color: transparent;
}
div.loaded p {
background-color: red;
}
.delay.delay-1s {
transition-delay: 1s;
}
.delay.delay-5s {
transition-delay: 5s;
}
Javascript
$(window).on('load', function(){
$('div').addClass('loaded');
});
$('button#change-delay').click(function() {
$('.delay').removeClass('delay-1s').addClass('delay-5s');
});
I tested this on Chrome/Firefox updated to this day (Sep 2017), but both returned the same result.
edit1:
I'm pretty sure this has something to do with the time to provide class name.
If I add the class btn-pressed in HTML, i.e hardcode them on the document, override works as intended. Although, it wouldn't happen exclusively when the class is modified.
edit2:
Added clarification.
edit3:
Narrowed down question.
edit4:
adding timelapse of event happening on code:
Loads document.
P gets background-color: transparent and transition-delay: 1s;
Loading is done, adding class 'loaded' to DIV,
P gets background-color: red and fires css-transition
BUTTON gets clicked*, adding class 'btn-pressed' to DIV.
P gets transition-delay: 5s; assigned, overrides CSSOM; however, since css-transition from 2. is already in action, it doesn't take effect.
*Surely, if BUTTON has clicked before loading completed, it will take effect.
I was too lazy to read W3C documents but maybe that's what I should do in spare time..
Html code here
<div class="bg">
<p>test here</p>
</div>
<button class="btn">Activate</button>
Css code here
.bg {
min-height: 200px;
background-color: transparent;
}
Js code here
$(window).on('load', function(){
var delay = 5000;
If ( $('.bg').hasClass('pressed') ) {
delay = 2000; //set delay to 2 sec,
}
$('.btn').on('click', function() {
$('.bg').addClass('pressed');
});
$('.bg').animate({
'background-color': 'red'
}, delay);
});
I assume that you have jquery. If any issue plz let me know by putting a comment below.
I hope this is what you need.
Note - Make few changes as per you needs like class name and events.

AngularJS temporarily disable animations

I have a pretty complex ng-repeat. The number of displayed items can be controlled by two buttons. The first button removes a single element from the ng-repeat by using a filter. The second button removes a bunch of elements and displays a bunch of other elements (also by using a filter).
I currently have an animation on the ng-repeat like this:
<style>
.animation {
-webkit-transition: 1s;
}
.animation.ng-enter {
opacity: 0;
}
.animation.ng-enter.ng-enter-active {
opacity: 1;
}
/* Similar for ng-leave */
</style>
<div class="animation" data-ng-repeat="item in items"> ... </div>
When the user clicks the first button I want the elements to use the animation.
When the user clicks the second button I want to disable any animations.
I'm using AngularJS 1.2.16.
You could use ng-class directive to have animation class conditionally. Remove animation class when you don't want it, specifically saying on click of second button.
<div ng-class="{animation: expression }" data-ng-repeat="item in items"> ... </div>
In above snippet expression will be condition/scope variable which will set to false so that animation will get removed and animation will get disabled.

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.

Resources