ngAnimate not adding classes to image gallery using ngRepeat - angularjs

Demo: http://plnkr.co/edit/gehNa1s62ipRcny5Uzkj?p=preview
I'm attempting to make my image gallery animate when you hit the left/right arrows. Ideally, they would work like they do here.
I tried doing this:
.gallery-image {
opacity: 1;
&.ng-enter {
transition: transform 0.5s;
opacity: 0;
}
&.ng-enter-active {
opacity: 0.5;
}
}
But it just seems like ngAnimate doesn't want to add any classes to my elements on the DOM. My repeater is declared like this:
<img class="gallery-image"
ng-repeat="image in images | limitTo:3:currentIndex-1"
ng-show="$index+currentIndex-1 >= 0 && $index+currentIndex-1 < images.length"
ng-src="{{images[$index+currentIndex-1].url}}" />
So what I do is just change the current index I'm looking at, and that adjusts what images are visible.
The weird thing is, if you resize the plunk (sm to md, md to lg) you can see the images very clearly animating.
Why isn't ngAnimate adding any classes to my DOM?

It seems that ngAnimate will not do anything unless you actually modify the underlying array. The solution here is to keep a list of "visible" items, and modify that, instead of basing everything off of the currently visible index.

Related

Creating an animated 1-3 column layout using Angular

Here's the situation:
I'm building a page for an application which consists of a navbar, a footer and a 3 column body.
Initially, only one column should be shown. This first column will be filled with clickable divs (let's call them cards). When one of these cards is clicked, the second column should slide open from the side, revealing more information about the clicked card.
The same workflow applies to the second column: the details displayed in the second column contains its own cards, which - when clicked - open up the third column with more details about the card in the second column.
The second and third column can also be closed, while the first can not.
I'm loading the column information using Angular, and so far I've had no real struggle implementing the 1-3 column layout.
But when I try to make this work smooth - e.g. using animations - things get weird. I don't really know how I can animate the (dis)appearance of one of each columns.
Here's what I have so far: Codepen example
<div class="container" ng-controller="Controller as ctrl">
<div class="column" ng-repeat="column in ctrl.columns" ng-class="[column.mode, column.color]" ng-show="column.open">
<button ng-click="ctrl.close(this)" ng-show="column.id != 0">Close</button>
<p ng-click="ctrl.open(this)">Name: {{column.name}}</p>
<p>Open: {{column.open}}</p>
<p>Mode: {{column.mode}}</p>
<p>Color: {{column.color}}</p>
</div>
</div>
CSS:
.container {
height: calc(100% - 50px);
display: flex;
}
.column {
padding: 10px 0 0 10px;
overflow-y: auto;
}
.column-narrow {
flex: 33;
}
.column-wide {
flex: 66;
}
.column-full {
flex: 100;
}
The second and third column can be triggered by clicking the name paragraph.
Don't worry about the colors, they're definitely not final and are used only for a clear visual difference between containers etc.
Can any one of you offer me a CSS(3) solution to this? If my code can be optimised please do, as I'm currently learning Angular.
There is not a lot of code needed to get some basic animations working.
The ng-show and ng-hide directives already provide support for animations out of the box. That means that AngularJS will add animation hooks in the form of additional classes ng-hide-add, ng-hide-add-active, ng-hide-remove, ng-hide-remove-active.
So these classes get added to your CSS column.
I literally only had to add these CSS lines to make animations work in your Codepen.
.column.ng-hide-add.ng-hide-add-active,
.column.ng-hide-remove.ng-hide-remove-active {
-webkit-transition: all linear 0.5s;
transition: all linear 0.5s;
}
Here is the updated codepen:
http://codepen.io/anon/pen/XbVLxO

Does anyone else have trouble with angular and range sliders?

Seems to be an impossible task to find a range slider that works well with ng-repeat and can be displayed vertically. Anyone have ideas about what to try next?
I'm trying to make a took where you can manually control the brightness of a sign at each hour of the day. The current idea is to stack 24 vertical range sliders next to each other where each one controls the brightness for that hour and a 25th slider that is a master control that adjusts all 24 other sliders simultaneously.
The closest I came was with angular-rangeslider but it turned out to be incredibly buggy when used with ng-repeat. I suppose I could manually write out all 25 of them but I'd rather not.
The other idea is to use jqPlot because you can drag the datapoints. (It seems to be the only chart library where you can drag the datapoints too (please correct me if I'm wrong))
How about an HTML5 range input?
HTML:
<input type="range"
orient="vertical"
ng-repeat="slider in sliders"
ng-model="slider.val" />
CSS (necessary to make it vertical in some browsers):
input[type=range][orient=vertical] {
writing-mode: bt-lr; /* IE */
-webkit-appearance: slider-vertical; /* Webkit */
width: 20px;
height: 200px;
}
Works fine with Angular bindings. Here's a Plunker.
Supported browsers look to be IE10+ and most others.
I made an exemple in plunker of how i would use this
I create an array of empty object.
$scope.sliders = [];
for(var i=0; i<5; i++){
$scope.sliders.push({});
}
I display it using a ng-repeat using HTML range inputs
<span ng-repeat="slider in sliders track by $index">
<input ng-init="slider.value = 0" type="range" ng-model="slider.value">
{{slider.value}}
</span>
Maybe not elegant but i just use the rotation from CSS to make it vertical.
Note that you'll have to define a better css selector than "input"
input {
-ms-transform: rotate(-90deg); /* IE 9 */
-webkit-transform: rotate(-90deg); /* Chrome, Safari, Opera */
transform: rotate(-90deg);
width:70px;
height:100px;
}
Hope it helped

AngularJS 1.2 - ngAnimate not working

I am new to using ng-animate with AngularJS 1.2. I am not sure why my ng-animate does not work a certain class name but works with the default for a simple fade in that I saw in an example.
In this example, I try to set my ng-animate class to be 'animation':
http://plnkr.co/edit/QWQUUVdcLmzLKRvVibqN?p=preview
but when I use the default, and my class name for animations is just ".ng-enter" and ".ng-leave", the fade in animation seems to work fine.
http://plnkr.co/edit/lEQhMwd6RWmsdmJbosu0?p=preview
Any help would be greatly appreciated, thanks!
The ng-animate attribute is deprecated in 1.2.
In 1.2 you define the appropriate CSS classes using a special naming convention. If you want a specific name like 'animation', you need to add that class to the element you want to animate.
As long as you have the correct CSS classes, some directives will be animated automatically. Which ones can be found here: http://docs.angularjs.org/api/ngAnimate
This is the reason your animation works in your second example when just defining the ".ng-enter" class. This would however automatically animate all directives that support the enter animation.
I have updated your first example to make it work with the class named 'animation':
HTML:
<li ng-repeat="item in items" class="animation">{{item}}</li>
CSS (Keeping selectors ungrouped for clarity):
.animation {
-webkit-transition: 1s;
}
.animation.ng-enter {
opacity: 0;
}
.animation.ng-leave {
opacity: 1;
}
.animation.ng-enter.ng-enter-active {
opacity: 1;
}
.animation.ng-leave.ng-leave-active {
opacity: 0;
}
Plunker: http://plnkr.co/edit/J0qJEMmwdzqXzu733fJf?p=preview
Also important to remember to add the animation module as a dependency to your module definition. Just in case anyone else is having problems getting animations working and hasn't done this.
angular.module('myApp', ['ngAnimate']);
You must check that the version of your angular.min.js matches with the version of angular-animate.min.js.
I got mine fixed this way.
As Tasse said ng-animate is deprecated, we need to use the class.
If you are copying CSS from angularjs web site http://www.nganimate.org/angularjs/ng-repeat/move then you need to modify those CSS in a particular format
For complete detail check Apply Angularjs Animation in 2 minutes
This is in addition to accepted answer, for those who are trying to animate an element with ng-show directive. These are styles which must be used:
.animation.ng-hide-remove {
transition:2s linear all;
opacity:0;
}
.animation.ng-hide-remove.ng-hide-remove-active {
opacity:1;
}
Please note, not all angular directives adds ng-enter, ng-enter-active, ng-leave and ng-leave-active. For example, ng-show directive adds ng-hide-remove at the beginning of animation and ng-hide-remove-active at the end of it. For more details follow this link:
https://www.w3schools.com/angular/angular_animations.asp

What's a good way to move items in an list with AngularJS and ng-animate?

I want to be able to reorder a list, right now I have buttons on each item to move them up and down the list. I want to use ng-animate to make the items move smoothly, but I can only find the -move animation, and that apparently only works on the top element of the two that are switching places. I can't get it to look right. Here's what I have so far: Fiddle
.person-move {
transition: all 0.5s;
position: relative;
height: 0;
}
.person-move.person-move-active {
height: 26px;
overflow: hidden;
}
I guess I'm not sure of the purpose of -move. I'm swapping the places of two people, but it only seems to affect the top one. I'd like it to look like they are being swapped. in the sample fiddle there's a checkbox to create new objects instead of moving existing ones to fire -enter and -leave, maybe I could combine the two methods:
use -move for the top person (who used to be below), animating relative position upwards
use -enter for the bottom person by creating a new object, animating relative position
Is there an easier or better way to do this?
Other thoughts:
Something like jquery-ui's drag and drop would be nice, but I don't want to have to include it and find out if I can get it to work with AngularJS.
After a lot of messing around, I got it to work the way I wanted using the CSS next sibling selector, +: (Fiddle)
.person-move {
position: relative;
top: 26px;
}
.person-move.person-move-active {
transition: all 0.5s ease;
top: 0;
}
.person-move + div {
/* cannot have transition on this element */
/*transition: all 1s ease;*/
position: relative;
top: -26px;
}
.person-move.person-move-active + div {
transition: all 0.5s ease;
position: relative;
top: 0;
}
The key was to have the transition style only on the active class selectors. The examples I've seen like on yearofmoo have them on the base classes which I can't see any reason for since those are there solely to set up the initial condition for the animation I believe. Chrome doesn't like it anyway and tries to animate to the initial condition when using the sibling selector.

Fluid like box?

I'm making a responsive site and need to include a Facebook Like-Box for the client's Facebook fanpage. The developer page for the like-box has a widget for customization, but it doesn't allow you to set a width in percentages.
I've searched around and the closest I've got was this page from 2010, which refers to a fb:fan widget that allows you to link custom CSS. I tried to get this tutorial to work but it fails with this error:
<fb:fan> requires one of the "id" or "name" attributes.
So, to recap, I need a Facebook Like Box that I can either set up to be fluid, or which allows me to pass custom CSS to the iFrame it generates. Anyone able to point me in the right direction?
I found this Gist today and it works perfectly: https://gist.github.com/2571173
/* Make the Facebook Like box responsive (fluid width)
https://developers.facebook.com/docs/reference/plugins/like-box/ */
/* This element holds injected scripts inside iframes that in
some cases may stretch layouts. So, we're just hiding it. */
#fb-root {
display: none;
}
/* To fill the container and nothing else */
.fb_iframe_widget, .fb_iframe_widget span, .fb_iframe_widget span iframe[style] {
width: 100% !important;
}
You thought it couldn't be done? AHA! Have at you, Facebook and your wicked fixed-width ways: I wrote a JQuery script to undo all your evil!
$(document).ready(function(){
var fbWidth;
function attachFluidLikeBox(){
// the FBML markup: WIDTH is a placeholder where we'll insert our calculated width
var fbml = '<fb:like-box href="http://www.facebook.com/YOURFANPAGEORWHATEVS" width="WIDTH" show_faces="false" stream="true"></fb:like-box>';//$('#likeBoxTemplate').text().toString();
// the containing element in which the Likebox resides
var container = $('#likebox');
// we should only redraw if the width of the container has changed
if(fbWidth != container.width()){
container.empty(); // we remove any previously generated markup
fbWidth = container.width(); // store the width for later comparison
fbml = fbml.split('WIDTH').join(fbWidth.toString()); // insert correct width in pixels
container.html(fbml); // insert the FBML inside the container
try{
FB.XFBML.parse(); // parses all FBML in the DOM.
}catch(err){
// should Facebook's API crap out - wouldn't be the first time
}
}
}
var resizeTimeout;
// Resize event handler
function onResize(){
if(resizeTimeout){
clearTimeout(resizeTimeout);
}
resizeTimeout = setTimeout(attachFluidLikeBox, 200); // performance: we don't want to redraw/recalculate as the user is dragging the window
}
// Resize listener
$(window).resize(onResize);
// first time we trigger the event manually
onResize();
});
What is does is it adds a listener to the window's resize event. When it resizes, we check the width of the Likebox' containing element, generates new XFBML code with the correct width, replaces the containing element's children with said XFBML and then trigger the Facebook API to parse the XFBML again. I added some timeouts and checks to make sure it doesn't do anything stupid and only runs when it needs to.
Much has changed since the OP.
By simply choosing iFrame and setting your width to 100%, your FB Like Box should be responsive.
Basically FB adds this to the iFrame:
style="border:none; overflow:hidden; width:100%; height:300px;".
Been struggling with the exact same problem. A quick & simple solution is to use the iframe based Facebook Like box.
<iframe class="fb-like-box" src="//www.facebook.com/plugins/likebox.php?href=http%3A%2F%2Fwww.facebook.com%2Fplatform&width=292&height=500&colorscheme=light&show_faces=true&border_color&stream=true&header=true" scrolling="no" frameborder="0" allowTransparency="true"></iframe>
Note the assigned 'fb-like-box' class and all the removed inline styles. The class for the iframe could look something like this:
.fb-like-box {
width: 100% !important;
height:500px;
border:none;
overflow:hidden;
}
Looks like it doesn't matter what the height and width are that are defined in the iframe's src tag. Just place the iframe into some fluid element like a cell in a CSS grid layout.
(includes ideas from: http://updateox.com/web-design/make-facebook-comment-and-like-box-fluid-width/)
I used the HTML5 version of Facebook Like Box and here is what worked for me:
.fb-like-box,
.fb_iframe_widget span,
.fb_iframe_widget iframe {
width:100% !important;
}
You cannot set the like-box to anything other than a pixel width. My suggestion is to place it in a DIV or SPAN that is fluid with overflow set to hidden. Sure, it's going to crop off part of the like-box, but by having the requirement of fluid, this is your best bet.
Here's a small work around that appends the HTML5 Facebook LikeBox Plugin into the DOM with a response height or width.
$(document).ready(function(){
var height = $(window).height();
var width = $(window).width();
var widget_height = parseInt((height)*0.9);
var widget_width = parseInt((height)*0.3);
var page_url = "http://www.facebook.com/Facebook";
$(".fb-plugin").append("<div class='fb-like-box'
data-href='"+page_url+"'
data-width='"+widget_width+"'
data-height='"+widget_height+"'
data-colorscheme='dark'
data-show-faces='true'
data-border-color='#222'
data-stream='true'
data-header='true'>
</div></div>");
});
The comment above from Ed and Matthias about using 100% for the iframe worked great for me. Here is my iframe code
ORIGINAL WITHOUT FIX:
<iframe src="//www.facebook.com/plugins/likebox.php?
href=https%3A%2F%2Fwww.facebook.com%2FXXXXXXXXXX&
width&height=290&colorscheme=dark&
show_faces=true&header=true&stream=false&
show_border=true&appId=XXXXXXXXXX"
scrolling="no" frameborder="0"
style="border:none; overflow:hidden; height:290px;"
allowTransparency="true"></iframe>
UPDATED WITH 100% FIX:
<iframe src="//www.facebook.com/plugins/likebox.php?
href=https%3A%2F%2Fwww.facebook.com%2FXXXXXXXXXX&
width&height=290&colorscheme=dark&
show_faces=true&header=true&stream=false&
show_border=true&appId=XXXXXXXXXX"
scrolling="no" frameborder="0"
style="border:none; overflow:hidden; height:290px;width:100%"
allowTransparency="true"></iframe>
The only change is adding "width:100%" to the style attribute of the iframe
note that the code above has "XXXXXXXXXX" in place of the unique references

Resources