I have an AnuglarJS app, where I load/change some images from a webservice...
Controller
.controller(\'PlayerCtrl\', function($scope, programService
Update 1.5.x - with Angular 1.5.x you can use ngAnimateSwap to achieve this effect.
I know its late but according to @Aides answer i am posting here an working example that how can you achieve animation with change in ng-src
using ngAnimateSwap
(with Angular 1.5.x). I hope this helps someone in future:
HTML Markup:
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Example - example-ngAnimateSwap-directive-production</title>
<link href="animations.css" rel="stylesheet" type="text/css">
<script src="//code.angularjs.org/snapshot/angular.min.js"></script>
<script src="//code.angularjs.org/snapshot/angular-animate.js"></script>
<script src="script.js"></script>
<script type="text/javascript">
angular.element(document.getElementsByTagName('head')).append(angular.element('<base href="' + window.location.pathname + '" />'));
</script>
</head>
<body ng-app="ngAnimateSwapExample" ng-controller="AppCtrl">
<div class="container">
<img ng-animate-swap="activeImage" class="cell swap-animation" ng-src="{{activeImage}}" alt="My Active Image" />
</div>
<div>
Current Image: {{activeImage}}
<br />
<button ng-click="previous()">Previous</button>
<button ng-click="next()">Next</button>
</div>
</body>
</html>
JS (script.js)
:
(function(angular) {
'use strict';
angular.module('ngAnimateSwapExample', ['ngAnimate'])
.controller('AppCtrl', ['$scope', '$timeout', function($scope, $timeout) {
var baseUrl = "http://lorempixel.com/400/200/sports";
$scope.images = [];
$scope.startIndex = 0;
for (var i = 0; i < 5; i++) {
$scope.images.push(baseUrl + "/" + i);
}
$scope.activeImage = $scope.images[$scope.startIndex];
/*
$interval(function() {
$scope.startIndex++;
if($scope.images[$scope.startIndex] && $scope.images[$scope.startIndex] != undefined){
$scope.activeImage = $scope.images[$scope.startIndex];
}
}, 2000);
*/
$scope.previous = function() {
$scope.startIndex--;
$timeout(function() {
if ($scope.images[$scope.startIndex] && $scope.images[$scope.startIndex] !== undefined) {
$scope.activeImage = $scope.images[$scope.startIndex];
}
}, 500);
};
$scope.next = function() {
$scope.startIndex++;
$timeout(function() {
if ($scope.images[$scope.startIndex] && $scope.images[$scope.startIndex] !== undefined) {
$scope.activeImage = $scope.images[$scope.startIndex];
}
}, 500);
};
}]);
})(window.angular);
Working plunker here.
You can't animate an img src
change. You can, however, have multiple images and animate their opacity.
<div class="image-container">
<img src="image-one.jpg" ng-show="showImageOne">
<img src="image-two.jpg" ng-show="showImageTwo">
</div>
.image-container {
position: relative;
}
.image-container img {
position: absolute;
transition: 1s opacity linear;
}
.image-container img.ng-hide {
display: block!important;
opacity: 0;
}
In case others end up here wanting to perform animations on change of a background image, I'll post what I ended up using.
This directive assumes it's attached to a template like this:
<!-- Full screen background image and scarecrow for onload event-->
<div class="full-screen-image" data-background-image="{{backgroundImageUrl}}"></div>
<img class="hidden-full-screen-image hidden" data-ng-src="{{backgroundImageUrl}}"></div>
We want to set the background image source for the <div>
, but attach an onload event so we know when the new image has arrived. To do that, we use an <img>
with a .hidden
class that has .hidden {display: none;}
. Then we use the following directive to dynamically set the div's background image source and perform a fade to white then back from white on image change:
/***
*
* Directive to dynamically set background images when
* controllers update their backgroundImageUrl scope
* variables
*
* Template: <div data-background-image="{{backgroundImageUrl}}" />
* AND <img data-background-image="{{backgroundImageUrl}}" class="image-onload-target hidden" />
*
***/
var angular = require('angular');
angular.module('BackgroundImage', [])
.directive('backgroundImage', [
"$timeout",
function ($timeout) {
return function(scope, element, attrs){
attrs.$observe('backgroundImage', function(value) {
/***
*
* Define a callback to trigger once the image loads.
* The value provided to this callback = the value
* passed to attrs.$observe() above
*
***/
var imageLoadedCallback = function(value) {
// once the image load event triggers, remove the event
// listener to ensure the event is called only once
fadeOut();
target.removeEventListener('load', imageLoadedCallback);
$timeout(function() {
fadeIn(value);
}, 700);
}
/***
*
* Define fade in / out events to be called once a new image
* is passed to the attrs.backgroundImage in the directive
*
***/
var fadeOut = function() {
element.css({'opacity': '0'})
};
var fadeIn = function(value) {
element.css({
'background': 'url(' + value +') no-repeat center center fixed',
'background-size' : 'cover',
'opacity': '1'
});
};
// add an onload event to the hidden-full-screen-image
var target = document.querySelector('.image-onload-target');
target.addEventListener('load', imageLoadedCallback(value));
});
};
}]);
Working with Angular makes me love React all the more...
My solution to this problem is to watch for changes on ng-src and using a timeout function to add a class which does the fadeIn effect.
HTML
<img ng-src="your-logic-will-go-here" class="animate-show ng-hide-add" fade-in>
Angular Code
.directive('fadeIn', function($timeout){
return {
restrict: 'A',
link: function($scope, $element, attrs){
$scope.$watch('selectedFormat.name', function(newValue, oldValue) {
if(newValue!=oldValue) {
$element.removeClass("ng-hide-add");
$element.addClass("ng-hide-remove");
$timeout(function () {
$element.addClass("ng-hide-add");
}, 100);
}
})
}
};
})
CSS
.animate-show.ng-hide-add, .animate-show.ng-hide-remove {
display: inline-block !important;
}
.animate-show.ng-hide-add.ng-hide-add-active, .animate-show.ng-hide-remove {
opacity: 0;
}
.animate-show.ng-hide-add{
transition: all linear 0.7s;
}
.animate-show.ng-hide-add, .animate-show.ng-hide-remove.ng-hide-remove-active {
opacity: 1;
}
As christoph has mentioned, you should watch using $watch
on the image source change.
But first make sure you use the ng-src
rather than the src
for the image
tag.
<image id="new" ng-src="program.image" />
$scope.$watch('program.image', function(newValue, oldValue) {
if(newValue===oldValue) return;
$('img#new').hide();
$('img#new').fadeIn("slow", function() {});
})