angularjs - example - framework angular
Dos animaciones diferentes para cambios de ruta. (5)
Tengo el siguiente caso: Estoy usando el enrutador ui para el enrutamiento en mi aplicación AngularJS. En una ruta, hay cinco estados secundarios para diferentes subpantallas. Quiero animar la transición entre estos de manera similar a un carrusel.
La navegación se ve así:
Link to A | Link to B | Link to C | Link to D | Link to E
La navegación desde el state A
al state B
debería hacer que la screen A
deslice hacia la izquierda y la screen B
deslice desde la derecha; viceversa, para navegar desde el state B
al state A
Lo que funciona es animar las transiciones de pantalla con transform: translateX(...);
en enter
y leave
en una sola dirección.
Por lo general, controlo mis animaciones usando ng-class
con una bandera. Sin embargo, en este caso, establecer una clase en el elemento ui-view
no funciona en absoluto (Angular 1.2 y ui-router 0.2 aún no son completamente compatibles). Tampoco está funcionando configurándolo con una directiva personalizada que escuche el scope.$on "$stateChangeStart"
que se scope.$on "$stateChangeStart"
después de que la transición haya comenzado.
¿Cómo puedo implementar el comportamiento deseado?
Edición: la solución
Para el registro: terminé implementándolo usando una función de $scope
personalizada usando $state.go()
para determinar la dirección antes de cambiar la ruta. Esto evita los errores $digest already in progress
. La clase que determina la animación se agrega al elemento padre de ui-view
; Esto anima tanto la vista actual como la futura ui-view
en la dirección correcta.
Función del controlador (Coffeescript):
go: (entry) ->
fromIdx = ...
toIdx = ...
if fromIdx > toIdx
$scope.back = false
else
$scope.back = true
$state.go entry
Modelo:
<div ng-class="{toLeft: back}">
<div ui-view></div>
</div>
Estaba intentando hacer lo mismo con ngRoute
usando $routeChangeSuccess
pero el problema que encontré fue que la animación de ng-leave
comenzaría antes de que se ejecutara un ciclo de resumen. La animación de entrada siempre fue correcta, pero la animación de dejar siempre fue la anterior.
La solución que funcionó para mí (Angular 1.57) fue envolver la llamada $location.path()
en un $timeout
. Esto asegura que se ejecuta un resumen completo antes de que se inicie la animación.
function goto(path) {
if(nextIndex > currentIndex) {
ctrl.transition = ''slide-out-left'';
} else {
ctrl.transition = ''slide-out-right'';
}
$timeout(function() {
$location.path(path);
});
}
Intento similar a la respuesta aceptada de @eddiec. Básicamente se comparan una matriz de los valores de nombre de estado y luego la posición en la matriz de los nombres de los valores de toState y fromState para determinar la dirección.
.controller(''viewCtrl'', function ($scope) {
$scope.$on(''$stateChangeSuccess'', function (event, toState, toParams, fromState, fromParams) {
// create an array of state names, in the order they will appear
var states = [''state1'', ''state2'', ''state3''];
if (states.indexOf(toState.name) < states.indexOf(fromState.name)) {
$scope.back = true;
}
else {
$scope.back = false;
}
});
});
Codepen, bifurcado desde arriba, mostrando el resultado de trabajo. http://codepen.io/anon/pen/zBQERW
La solución de Eddiec fue un buen comienzo, pero todavía me encontré hackeando un poco. Aquí hay un controlador modificado que funciona mejor para mis propósitos. Esto es más dinámico:
function ViewCtrl($scope, $state) {
$scope.$on(''$stateChangeStart'', function (event, toState) {
var movingToParent = $state.includes(toState.name);
if (movingToParent) {
$scope.back = true;
} else {
$scope.back = false;
}
});
}
Puede controlar las clases en su vista configurando un controlador para hacer eso específicamente. Luego puede suscribirse a eventos dentro de la aplicación y cambiar la forma en que se anima la página.
<div class="viewWrap" ng-controller="viewCtrl">
<div class="container" ui-view ng-class="{back: back}"></div>
</div>
Luego dentro de tu control
.controller(''viewCtrl'', function ($scope) {
$scope.$on(''$stateChangeSuccess'', function (event, toState) {
if (toState.name === ''state1'') {
$scope.back = true;
} else {
$scope.back = false;
}
});
});
He configurado un codepen para demostrar aquí http://codepen.io/ed_conolly/pen/aubKf
Para cualquiera que intente hacer esto, tenga en cuenta que he tenido que usar el módulo ui.router.compat debido a la incompatibilidad actual de las animaciones en Angular 1.2 y UI Router.
Siempre puede verificar la rama angular-1.2: https://github.com/angular-ui/ui-router/tree/angular-1.2 . Esto corrige ngAnimate junto con algunas otras cosas.
Creo que esto se incluirá en ui-router 0.3.0, por lo que siempre y cuando no esté presionando en vivo pronto, esto le proporcionará la función que necesita hasta que pueda volver a la rama ''estable''.
Descargo de responsabilidad: no tengo autoridad sobre cuándo será la próxima versión de UI-router o qué incluirá. Simplemente he encontrado esta información en varios temas en la página de github.