referencia org docs descargar apps javascript angularjs angularjs-scope angular-ui-router ng-animate

javascript - descargar - https docs angularjs org/>



El ciclo de resumen de AngularJS ocasionalmente falla al actualizar el alcance (1)

Desarrolladores Angulares!

Me encuentro con un problema cuando uso ngAnimate y UI-Router juntos. Básicamente, tengo cinco estados secundarios ("diapositivas") que componen mi contenido principal, así como un botón en cada lado. Estos botones van a las diapositivas anterior y siguiente respectivamente al hacer clic.

Estoy usando traducciones CSS3 para animar la entrada y salida de las diapositivas. Cuando el usuario hace clic en el botón izquierdo, la diapositiva actual sale hacia la derecha y la diapositiva "anterior" ingresa desde la izquierda. Lo contrario ocurre cuando se hace clic en el botón derecho: la diapositiva actual sale hacia la izquierda y la diapositiva "siguiente" entra desde la derecha. Estas diapositivas giran alrededor, por lo que la diapositiva cero va a la diapositiva cuatro y viceversa.

La dirección en la que entran y salen las diapositivas (tenga en cuenta que las diapositivas son estados UI-Router, por lo que se eliminan del DOM al final de las animaciones) está determinada por una clase que aplico al elemento padre. Al aplicar la clase "izquierda", las diapositivas se animan hacia la izquierda y viceversa hacia la clase "derecha".

El código está dividido en varios elementos:

  • appSlideDirective
    • directiva que contiene botones deslizantes y una interfaz de usuario embebida UI Router div (contenido)
    • maneja el botón de usuario presiona y pasa eventos de clic a baseController para transiciones de estado
  • baseController
    • controlador que pertenece al módulo principal, gestiona el estadoServicio
  • stateService (solo utilizado por baseController)
    • navega entre estados UI-Router cuando la directiva lo envía eventos
  • slideService (solo utilizado por la directiva)
    • gestiona la adición y eliminación de la clase "izquierda" y "derecha" (mediante ng-clic)

Directiva HTML:

<div id="slide-container"> <div id="slide" data-ng-class="{ left: slide.getTransitionState().left, right: slide.getTransitionState().right }"> <div id="slide-content" data-ui-view></div> </div> </div>

Código de referencia relevante:

angular.module(''app'').directive(''appSlide'', function(slideService) { restrict: ''A'', scope: { currentState: ''='', numberOfStates: ''='', loadPreviousState: ''&onPreviousState'', loadNextState: ''&onNextState'' }, templateUrl: ''slide.html'', link: function(scope, element) { scope.$on(''$destroy'', function() { element.empty(); }); }, controller: function($scope, $timeout) { var vm = this; // ... vm.loadPreviousSlide = function() { slideService.preparePreviousSlide(); $scope.loadPreviousState(); }); vm.loadNextSlide = function() { slideService.prepareNextSlide(); $scope.loadNextState(); }); vm.getTransitionState = function() { return slideService.getTransitionState(); }; // ... }, controllerAs: ''slide'' });

Código de controlador relevante:

angular.module(''app'').controller(''baseController'', function(stateService) { var vm = this; // ... vm.loadPreviousState = function() { stateService.loadPreviousState(); }; vm.loadNextState = function() { stateService.loadNextState(); }; // ... });

Código de servicio relevante:

angular.module(''app'').factory(''slideService'', function() { var _transitionState = { left: false, right: false }; return { preparePreviousSlide: function() { _transitionState.right = false; _transitionState.left = true; }, prepareNextSlide: function() { _transitionState.left = false; _transitionState.right = true; }, getTransitionState: function() { return _transitionState; } // ... }; }); angular.module(''app'').factory(''stateService'', function($state) { // ... return { // ... loadPreviousState: function() { var targetState = _calculatePreviousState(); $state.go( targetState ); }, loadNextState: function() { var targetState = _calculateNextState(); $state.go( targetState ); } // ... }; });

Esto funciona bastante bien, en su mayor parte. La primera transición de diapositiva no se anima en la carga de la página, ya que ni la clase ''izquierda'' ni la clase ''derecha'' están presentes. Del mismo modo, cambiar de dirección (es decir, ir a la izquierda dos veces, luego a la derecha una vez) hace que las diapositivas aparezcan desde el lado equivocado, ya que la clase "izquierda" / "derecha" de la animación anterior todavía está en el elemento.

Después de algunas excavaciones, creo que he tropezado con por qué fallan las animaciones primera / opuesta: el evento ng-click inicia un ciclo de resumen que bloquea cualquier cambio de alcance hasta que se completan todas sus acciones, lo que significa que el estado es cambiado antes de la clase adecuada ''izquierda'' / ''derecha'' y se pueden aplicar sus correspondientes estilos de transformación CSS3. Por lo tanto, necesito ejecutar otro ciclo de resumen una vez que haya actualizado correctamente las clases ''izquierda'' y ''derecha'' y solo luego cambie el estado.

Realicé muchas iteraciones de código y mi implementación actual se basa en $ scope. $ Apply y el $ timeout service. Para forzar otro ciclo de resumen, ejecuto $ scope. $ Apply - y uso $ timeout para evitar errores "en curso". Luego ejecuto mis cambios de estado cuando se supera la promesa de $ timeout.

Actualizaciones relativas a directivas

vm.loadPreviousSlide = function() { var promise = $timeout(function() { $scope.$apply(function() { slideService.preparePreviousSlide(); }); }, 0, false); promise.then(function() { $scope.loadPreviousState(); }); }; vm.loadNextSlide = function() { var promise = $timeout(function() { $scope.$apply(function() { slideService.prepareNextSlide(); }); }, 0, false); promise.then(function() { $scope.loadNextState(); }); };

Tengo dos problemas con esto. En primer lugar, ofende mi sensibilidad; me parece más complicado de lo que debe ser. En segundo lugar, no funciona el 100% del tiempo. Algunas veces funciona, y otras no. No tengo idea de por qué falla.

¿Qué piensan ustedes? ¡Avíseme si encuentra alguna solución mejor o si puede descubrir por qué la mina ocasionalmente falla! Gracias por tu tiempo.

Ah, una última cosa: soy bastante nuevo en AngularJS, así que no dude en dar recomendaciones sobre la estructura del código o la metodología.


Resolví este problema hace un par de meses.

Me vi obligado a implementar una solución que se sentía claramente menos "angular", pero funciona el 100% del tiempo.

Para resumir, terminé agregando y eliminando las clases de forma manual en lugar de esperar el próximo ciclo de resumen.

Por ejemplo:

var slide = angular.element(document.querySelector(''#slide'')); slide.removeClass(''right''); slide.addClass(''left'');

Entonces fue trivial desencadenar las transiciones de estado apropiadas.