在 ng-repeat 动画之前将 Angular ng-class 设置为 $apply [英] Getting Angular ng-class to $apply before an ng-repeat animation
问题描述
我有一个动画,可以根据单击的按钮向左或向右移动 ng-repeat 中的元素.
在一次操作中,我设置了一个 ng-class(动画类),然后移除了触发动画的元素,但在应用动画之前它似乎无法识别对 ng-class 的更改,除非我使用 $scope.$apply()
,但这会引发 $apply already in progress
错误.有没有办法不必使用 $scope.$apply()
,或者摆脱那个错误?
这是工作小提琴(有错误).http://jsfiddle.net/noducks/6pFr2/
HTML
<div ng-repeat="元素中的元素" ng-class="elem.anim"><button ng-click="out(elem, 'left', $index)">左</button><button ng-click="out(elem, 'right', $index)">Right</button>
Javascript
var myApp = angular.module('myApp',['ngAnimate']);函数 MyCtrl($scope) {$scope.elements = [{动画:''},{动画:''},{动画:''},{动画:''},{动画:''}];$scope.out = 函数(元素,目录,索引){elem.anim = direc;$scope.$apply();$scope.elements.splice(index, 1);};}
CSS
.left.ng-leave {-webkit-transition:所有线性 1;过渡:所有线性1s;}.left.ng-leave.ng-leave-active{-ms-transform: translateX(-100%);-o-transform: translateX(-100%);-moz-transform: translateX(-100%);-webkit-transform: translateX(-100%);变换:translateX(-100%);}.left.ng-离开{-ms-transform: translateX(0%);-o-transform: translateX(0%);-moz-transform: translateX(0%);-webkit-transform: translateX(0%);变换:translateX(0%);}.right.ng-离开{-webkit-transition:所有线性 1;过渡:所有线性1s;}.right.ng-leave.ng-leave-active {-ms-transform: translateX(100%);-o-transform: translateX(100%);-moz-transform: translateX(100%);-webkit-transform: translateX(100%);变换:translateX(100%);}.right.ng-离开{-ms-transform: translateX(0%);-o-transform: translateX(0%);-moz-transform: translateX(0%);-webkit-transform: translateX(0%);变换:translateX(0%);}
问题是,如果从 DOM 中删除重复元素,则它们没有任何 css 动画信息.我想您已经注意到,如果您删除 $apply
调用,元素会立即从 DOM 中删除.此外,您可能已经注意到,如果您对动画进行硬编码,动画会按预期发生,例如设置 class="left"
或 class="right"
.
要使 ngAnimation
像您期望的那样发生,$animate
服务和浏览器需要您尝试制作动画的信息.但是只有在 DOM 操作发生时,浏览器和 $animate
服务才知道这些信息.
如何解决这个问题:您需要在 DOM 更新 css 类后对 $scope.elements
进行更改.因此,您需要延迟一个摘要循环的 DOM 操作.这可以通过 $timeout
服务完成(有关更多信息,请参阅此答案AngularJS:$evalAsync 与 $timeout):
$scope.out = function(elem, direc, index) {elem.anim = direc;$超时(功能(){$scope.elements.splice(index, 1);});};
I have an animation that animates an element in an ng-repeat to the left or right depending on which button is clicked.
In one manoeuvre, I set a ng-class (the animation class) and then remove the element, which triggers the animation, but it doesn't seem to recognise the change to the ng-class before the animation is applied, unless I use a $scope.$apply()
, but this throws up a $apply already in progress
error. Is there a way to not have to use the $scope.$apply()
, or to get rid of that error?
Here is the working fiddle (with errors). http://jsfiddle.net/noducks/6pFr2/
HTML
<div ng-controller="MyCtrl" style="text-align: center">
<div ng-repeat="elem in elements" ng-class="elem.anim">
<button ng-click="out(elem, 'left', $index)">Left</button>
<button ng-click="out(elem, 'right', $index)">Right</button>
</div>
</div>
Javascript
var myApp = angular.module('myApp',['ngAnimate']);
function MyCtrl($scope) {
$scope.elements = [
{anim: ''},
{anim: ''},
{anim: ''},
{anim: ''},
{anim: ''}
];
$scope.out = function(elem, direc, index) {
elem.anim = direc;
$scope.$apply();
$scope.elements.splice(index, 1);
};
}
CSS
.left.ng-leave {
-webkit-transition:all linear 1s;
transition:all linear 1s;
}
.left.ng-leave.ng-leave-active{
-ms-transform: translateX(-100%);
-o-transform: translateX(-100%);
-moz-transform: translateX(-100%);
-webkit-transform: translateX(-100%);
transform: translateX(-100%);
}
.left.ng-leave {
-ms-transform: translateX(0%);
-o-transform: translateX(0%);
-moz-transform: translateX(0%);
-webkit-transform: translateX(0%);
transform: translateX(0%);
}
.right.ng-leave {
-webkit-transition:all linear 1s;
transition:all linear 1s;
}
.right.ng-leave.ng-leave-active {
-ms-transform: translateX(100%);
-o-transform: translateX(100%);
-moz-transform: translateX(100%);
-webkit-transform: translateX(100%);
transform: translateX(100%);
}
.right.ng-leave {
-ms-transform: translateX(0%);
-o-transform: translateX(0%);
-moz-transform: translateX(0%);
-webkit-transform: translateX(0%);
transform: translateX(0%);
}
The problem is that your repeated elements do not have any css animation information if they are removed from the DOM. I guess you have noticed that the elements are immediately removed from the DOM if you remove the $apply
call. Also you may have noticed that the animation happens as expected if you hardcode the animation e.g. set class="left"
or class="right"
.
To make the ngAnimation
happen as you expect the $animate
service and the browser need the information what you are trying to animate. But these informations are known to the browser and the $animate
service only when the DOM manipulations has taken place.
How to solve this: you need to make the changes to the $scope.elements
after the css class is updated at the DOM. So you need to delay the DOM manipulation for one digest loop. This can be done by the $timeout
service (please see this answer for more information AngularJS : $evalAsync vs $timeout):
$scope.out = function(elem, direc, index) {
elem.anim = direc;
$timeout(function(){
$scope.elements.splice(index, 1);
});
};
这篇关于在 ng-repeat 动画之前将 Angular ng-class 设置为 $apply的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!