I have a simple problem with angularui bootstrap's collapse directive. I have a <select> menu. When the someone changes the menu, the content changes. However, I would like to add an animation before applying these changes. Specifically, I would like for the section to collapse and uncollapse before showing the new content. I can collapse it, but I would like to know how to detect when the collapse has finished so I can uncollapse it.
I could use the $timeout method that I currently use, but it feels "hackish" and "incorrect," because if the time for the collapse animation changes, then I have to change the time again.
Relavent code:
.directive("myBufferAnimation", function($timeout) {
var ignoreFirst = true;
return function(scope, element, attrs) {
scope.$watch("selectBuffer", function(newValue) {
if (ignoreFirst) {
ignoreFirst = false;
return;
}
scope.toCollapse = true;
// Detect end of animation here?
// Bogus solution, as this just waits for one second rather than listening for the end of animation
$timeout(function() {
scope.selected = newValue;
scope.toCollapse = false;
}, 1000);
});
}
});
Looking at the angularui bootstrap's collapse directive, it does the animation using the $transition service but it doesn't expose away to hook into the promise return by the service. It does however change the class name of the element that has the collapse directive on it. You can use that to determine when the collapse animation has completed by putting a watch on the class attribute of the element.
Below is a working example of the code watching the class on the element. I made a change to use ng-change to execute the animation instead of the watching the selectBuffer. This eliminates the need for the ignoreFirst variable.
angular.module("testApp", ["ui.bootstrap"]).controller("TestCtrl", function($scope) {
// This would actually be fetched from an ajax call
$scope.data = [{
"title": "Title 1",
"content": "Content 1"
}, {
"title": "The Second Title",
"content": "Some content goes here"
}, {
"title": "Title 3",
"content": "Content 3"
}];
$scope.selected = $scope.data[0];
$scope.selectBuffer = $scope.data[0];
$scope.toCollapse = false;
}).directive("myBufferAnimation", function($timeout) {
return function(scope, element, attrs) {
scope.valueChanged = function() {
scope.toCollapse = true;
// save off the unregister method returned from $watch call.
var unregisterWatch = scope.$watch(function() {
return element.attr('class');
}, function(newClass, oldClass) {
// If the newClass is 'collapse' and the oldClass is 'collapsing'
// this means that the collapsing animation has completed.
if (newClass.indexOf("collapse") !== -1 && oldClass.indexOf("collapsing") !== -1) {
scope.selected = scope.selectBuffer;
scope.toCollapse = false;
// unregister the $watch on the class attribute
// since it is no longer needed.
unregisterWatch();
}
});
};
}
});