I am using ngAnimate to animate entries in an ng-repeat. When loading the data all elements are animated as I have defined in my css:
.chat-message.notice.ng-enter {
-webkit-animation: rubberBand 1s;
-moz-animation: rubberBand 1s;
-ms-animation: rubberBand 1s;
animation: rubberBand 1s;
}
This works when a notice is appended with the following html:
<ul>
<li class="media chat-message pointer fade-animate"
ng-repeat-start="message in guestbook.messages track by $index"
ng-if="!message.bot">
<!-- more html -->
</li>
<li class="chat-message notice" ng-repeat-end ng-if="message.bot">
<div>
<p class="text-center">
{{ message.message }}
<small>({{ message.date | amTimeAgo }})</small>
<span class="close pull-right" ng-click="guestbook.remove(message)">×</span>
</p>
</div>
</li>
</ul>
However, when a new message is appended (at the top), every element is again animated. Is there a way that elements animate only once? That when a new message is appended to the array, only that element will animate?
JSFIDDLE
EDIT
After a few clicks on a 'new message', I can see not all notices are animated. Maybe it has something to do with the ng-repeat-start and ng-repeat-end?
If understood correctly just change this:
$scope.messages.unshift(message);
to this:
$scope.messages.push(message);
Even above answer fixed the problem, my solution might be helpful in other scenarios. The fix is pretty straightforward.
Use Angular varible $first and just add CSS class for the first element using ng-class directive in your HTML. In this example, class "first" will be added only to first element in ng-repeat:
ng-class="{'first': $first===true}"
and then apply animation rules to element with "first" CSS class
.chat-message.notice.first.ng-enter {
color:red !important;
font-weight:bold;
animation: rubberBand 1s;
}
Updated JSFIDDLE: http://jsfiddle.net/t6x3a1zj/7/
Related
I've been experimenting with HTMX recently and I cant seem to find a way to apply a transition to a target element. I have a form that submits a GET request and returns a table.
<form class="mt-3" hx-get="/data/statement/AJAX" hx-target="#statementAJAX" >
It basically returns a div containing the table like this:
<div id="statementAJAX" class="fade-in">
</div>
the CSS for the div is the following:
.fade-in {
opacity: 1;
animation-name: fadeInOpacity;
animation-iteration-count: 1;
animation-timing-function: ease-in;
animation-duration: 0.5s;
}
#keyframes fadeInOpacity {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
Now the css transition works when i first load the page but when I execute the AJAX request nothing happens.
I tried apllying style="opacity:0" to the form but obviously it applies only to the form and not the target...
Any idea how to apply the transition to the target element?
What you have there works for me. Are you trying to replace the entire table or add to the table?
This works for me using your CSS and hx-swap="outerHTML" to replace the table.
<a href="#" id="test" hx-get="/load.html" hx-target="#table" hx-trigger="click" hx-swap="outerHTML">
Submit
</a>
<div id="table" class="fade-in"></div>
load.html
<div id="table" class="fade-in">
table content
</div>
Our team has created a widget in ServiceNow that shows a row of icons and show/hide additional details in a div when icons are clicked. This is what our html and client controller looks like:
<div class="icons">
<ul class="flex justify-content-center align-items-center">
<li ng-repeat="item in c.data.linksArray track by $index">
<a class="link" href="javascript:void(0)" ng-click="c.getInfo(item)">
<i title="{{item.titles}}" class='fa {{item.icon}} fa-3x circle-icon'></i>
</a>
</li>
</ul>
</div>
<div class="linkList text-center"
ng-repeat="thing in c.data.linksArray track by $index"
ng-if="thing.isVisible==true">
<ul>
<li class="m-b-sm" ng-repeat="link in thing.links">
{{link.link_title}}
</li>
</ul>
</div>
function($scope) {
/* widget controller */
var c = this;
c.getInfo = function(item) {
var isDisplaying = false;
if(item.isVisible== true){
isDisplaying = true;
}
for(var i=0; i<c.data.linksArray.length; i++){
c.data.linksArray[i].isVisible = false;
}
if(isDisplaying == true){
item.isVisible = false;
}else{
item.isVisible=!item.isVisible;
}
}
console.log('icon-link-list');
console.log($scope);
}
This all works fine, but we'd like to refine it by adding a sliding effect to the .linkList class. Right now, when an icon is clicked, the .linkList div appears very abruptly. Is there a way to add a sliding transition effect to that div using css?
You can solve this by pure css animations. Aplly this css to the item which will we hidden/shown. The animation will play anytime css attribute 'display' will change. I guess it's the linkList element?
.linkList {
animation: slideFromLeft .2s;
animation-timing-function: ease;
animation-fill-mode: forwards;
opacity: 0;
}
#keyframes slideFromLeft{
0% {
opacity: 0;
transform: translateX(50px);
}
100% {
opacity: 1;
transform: none;
}
}
Edit: you maybe have to change ng-if on linkList to ng-show.
From the Docs:
Animations in AngularJS are completely based on CSS classes. As long as you have a CSS class attached to an HTML element within your application, you can apply animations to it.
As ngRepeat does its thing, each time a new item is added into the list, ngRepeat will add an ng-enter class to the element that is being added. When removed it will apply an ng-leave class and when moved around it will apply an ng-move class.
For more information, see
AngularJS Developer Guide - Animations
Goal —
Smoothly animate a changing list of items.
Problem —
When an item enters the list, everything repositions smoothly. When an item leaves the list, everything snaps abruptly.
I've discovered that .drawer-move is applied when new items enter, but .drawer-move is not applied when items leave.
Docs: https://v2.vuejs.org/v2/guide/transitions.html#List-Move-Transitions
Template —
<transition-group class="utilities -animate" tag="section" name="drawer">
<div class="drawer" key="application-drawer">
<div class="heading">Select An Application</div>
</div>
<div class="drawer" v-if="selectCompanyVisible" key="company-drawer">
<div class="heading">Select A Company</div>
</div>
<div class="drawer" key="manage-drawer">
<div class="heading">Manage {{ user.id }}</div>
</div>
</transition-group>
CSS —
.drawer-enter-active,
.drawer-leave-active,
.drawer-move {
transition-property: opacity, transform;
transition-timing-function: cubic-bezier(0.5, 0, 0.5, 1);
transition-duration: .4s;
}
.drawer-enter,
.drawer-leave-to {
opacity: 0;
transform: translateX(3rem);
}
The -leave-active transition class must apply a position: absolute declaration, in order to take it out of the layout flow, so the siblings can move in to place around it.
https://forum.vuejs.org/t/transition-group-move-class-not-occuring-in-the-array/6381/4
This also could mean that you should declare positioning within the transition-group element. No one mentions this in the Vue team, but I don't find this applied automatically by the transition classes.
.drawer-leave-active {
position: absolute;
// optional, depends on your layout
left: 0;
width: 100%;
}
.utilities {
position: relative;
}
I've been playing with this for a while, but can anyone explain what the requirements are to have the tile-cascade page transition to work in Polymer? When I take a look at the code for the transition, I see the following:
polyfill-next-selector { content: ':host(.tile-cascade) > * [tile-cascade] > div:nth-of- type(2)'; }
:host(.tile-cascade) ::content > * /deep/ [tile-cascade] > div:nth-of-type(2) {
-webkit-transition-delay: 0.05s;
transition-delay: 0.05s;
}
polyfill-next-selector { content: ':host(.tile-cascade) > * [tile-cascade] > div:nth-of-type(3)'; }
:host(.tile-cascade) ::content > * /deep/ [tile-cascade] > div:nth-of-type(3) {
-webkit-transition-delay: 0.1s;
transition-delay: 0.1s;
}
I believe this tells us what the markup should be made of (IE: It's looking for divs after the element with the tile-cascade attribute, but I'm not sure if I'm missing other requirements. I've attached a screen shot of some of the code from Chrome dev tools in hopes that it will proved some context
From my experience, there are three things that you need to do.
People often forget to include the reference for the tile-cascade animation. So make sure you have <link rel="import" href="../bower_components/core-animated-pages/transitions/tile-cascade.html"> on top of your element.
You cannot apply the tile-cascade attribute to the direct child of your core-animated-pages. Apply it to the next level container.
Your core-animated-pages needs to include tile-cascade in the transitions attribute.
To demonstrate point 2 & 3, I have the following piece of code that works properly in my project.
<core-animated-pages selected="{{ $.tabs.selected }}" transitions="tile-cascade" notap fit>
<section>
<core-selector tile-cascade>
<div class="portal-item">
<div class="tile"></div>
</div>
<div class="portal-item">
<div class="tile"></div>
</div>
<div class="portal-item">
<div class="tile"></div>
</div>
<div class="portal-item">
<div class="tile"></div>
</div>
Update
4. As already mentioned in the OP, each tile element needs to be wrapped by a div.
Say if you are using a template to iterate through the tiles, you will need to wrap whatever inside your template with a div otherwise the tile-cascade won't work (Interestingly, the list-cascade animation works without the need of the div wrapper). e.g.
<core-animated-pages transitions="cross-fade tile-cascade">
<section>
<div class="container" horizontal layout center-justified wrap cross-fade tile-cascade>
<template repeat="{{item in hierarchyItems}}">
<!-- you need this div here otherwise the tile-cascade animation doesn't work! -->
<div>
<my-element></my-element>
</div>
</template>
</div>
</section>
I would like to add a CSS3 effect to my dropdown. (Just like that one in Instagram.com on "My profile").
I'm using Animate.css for the CSS3 effects.
I tried this, but it doesn't work.
HTML
<%=fa_icon "bell"%>
<ul id="dropdownalerts" class="f-dropdown text-left animated bounceInDown" data-dropdown-content>
<li><%=link_to "Facebook", "#"%></li>
<li><%=link_to "Email", "#" %></li>
</ul>
JS
$(document).ready(function(){
$('a').hover(function(){
$("ul").addClass('animated bounceInDown');
});
});
You can find a live version on Zapping.io
I got it working in an example. I used the HTML you provided, and then downloaded the bounceInDown animation and used that for the CSS in the examples below.
jsFiddle example here - hover method
jQuery
$(document).ready(function(){
$('a').hover(function() {
$("ul").addClass('animated bounceInDown');
},function(){
$("ul").removeClass('animated bounceInDown');
});
});
If you want to add a delay when hovering off, use something like this:
jsFiddle example - hover method with delay.
$(document).ready(function(){
$('a').hover(function() {
$("ul").addClass('animated bounceInDown');
},function(){setTimeout(function(){
$("ul").removeClass('animated bounceInDown');
}, 750);});
});
Those examples are assuming you want the animation fired on hover. If you want it fired on click, use something like this instead:
jsFiddle example click method - Look below for an alternative non-JS method.
$(document).ready(function(){
$('a').click(function() {
$("ul").toggleClass('animated bounceInDown');
});
});
Alternative method - No JS/jQuery
If you don't want to use JavaScript/jQuery, you can use the checkbox hack in CSS.
This essentially toggles between :checked, thus activating the animation.
jsFiddle example - It works in all current browsers.
HTML
<label id="click" for="dropdown">Click here</label>
<input style="display:none" type="checkbox" id="dropdown">
<ul id="dropdownalerts" class="f-dropdown text-left" data-dropdown-content>
<li>Facebook</li>
<li>Email</li>
</ul>
CSS - (only part of it) See the example above for full CSS.
input[type=checkbox]:checked ~ #dropdownalerts {
display:inline-block;
-webkit-animation: bounceInDown 1s both;
-moz-animation: bounceInDown 1s both;
-o-animation: bounceInDown 1s both;
animation: bounceInDown 1s both;
}