I created an animated slider with AngularJS and jQuery. The sliding animation works when run by clicking one of two buttons I included (Left and Right). The animation doesn't work when I try to fire it from a $swipe action.
In the swipe scenario $animate.addClass() doesn't add the class that should set off the animation.
You can try it here: http://plnkr.co/edit/oUVzHoR8kFHB3ZZAzPpQ?p=preview
First click on of the buttons and you will see the slides animating. Then drag over the slides with your mouse. In the browser console you will see 'move it!' which is printed right before the animation should start, but then... nothing happens. Do you know why?
Adding ng-swipe-left / -right attributes works by the way. But I want custom sliding behavior.
Here is the code for reference:
<!DOCTYPE html>
<html lang="en" ng-app="myApp">
<head>
<title>Test</title>
<script src="//code.jquery.com/jquery-2.1.1.min.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.7/angular.min.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.7/angular-animate.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.7/angular-touch.js"></script>
<script type="text/javascript">
var app = angular.module('myApp', ['ngAnimate', 'ngTouch']);
app.directive('sliderbox', ['$animate', '$swipe', '$log', function ($animate, $swipe, $log) {
return {
restrict: 'E',
replace: false,
link: function (scope, element, attrs) {
scope.moveLeft = function () {
move('move-left')
};
scope.moveRight = function () {
move('move-right')
};
function move(directionClass) {
$log.info("Starting moving " + directionClass);
if (directionClass != null) {
// Find child elements with the boxslide class
var slides = element.find('.boxslide');
// Get the left-most slide
var leftMostSlide = slides[0];
if ((!$(leftMostSlide).is(':animated'))) {
$log.info("Move it!");
$animate.addClass(leftMostSlide, directionClass).then(function () {
$(leftMostSlide).removeClass(directionClass);
});
}
}
}
var posX;
var posY;
$swipe.bind(element, {
'start': function (coords) {
posX = coords.x;
posY = coords.y;
},
'move': function (coords) {
},
'end': function (coords) {
var delta = coords.x - posX;
if (delta > 50) {
$log.info("Hit move right threshold");
scope.moveRight();
} else if (delta < -50) {
$log.info("Hit move left threshold");
scope.moveLeft();
}
},
'cancel': function (coords) {
// ..
}
});
}
};
}]);
app.animation('.boxslide', ['$log', function ($log) {
return {
addClass: function (element, className, done) {
var movePixels = 130; // (78px + 2 * 25px padding + 2 * 1px border)
var direction = '';
if (className === 'move-left') {
direction = '-=';
} else if (className == 'move-right') {
direction = '+=';
}
$log.info("MOVING: " + className);
element.animate({marginLeft: direction + movePixels}, 500, done);
}
}
}]);
</script>
<style>
sliderbox {
display: block;
border: 1px solid blue;
overflow: hidden;
white-space: nowrap;
}
.boxslide {
border: 1px solid gray;
background-color: #ececec;
padding: 25px;
width: 78px;
display: inline-block;
float: none;
vertical-align: top;
margin: 0;
}
</style>
</head>
<body>
<sliderbox>
<div class="boxslide">
<div>
Slide 1
</div>
</div>
<!--
This comment prevents white space between box slides
-->
<div class="boxslide">
Slide 2
</div>
<!--
This comment prevents white space between box slides
-->
<div class="boxslide">
Slide 3
</div>
</sliderbox>
<button ng-click="moveLeft()">Left</button>
<button ng-click="moveRight()">Right</button>
</body>
</html>
Ah. It's a scope thing, of course. When I use $scope.$apply it works. Still trying to wrap my head around Angular's scope and asynchronous events, but the updated 'end:' function below works for now.
Updated plunker: http://plnkr.co/edit/H3JykOMteGPOHhGcu9fw?p=preview
'end': function (coords) {
var delta = coords.x - posX;
if (delta > 50) {
$log.info("Hit move right threshold");
scope.$apply(function(){
scope.moveRight();
});
} else if (delta < -50) {
$log.info("Hit move left threshold");
scope.$apply(function(){
scope.moveLeft();
});
}
},