speed left from esm bootstrap jquery angularjs angularjs-directive angularjs-ng-repeat swiper

jquery - left - swiper slider speed



Script de jQuery Swiper para ejecutar después de que se carguen elementos Ng-Repeat (3)

Estoy haciendo una aplicación web usando AngularJS, jQuery, HTML, CSS y Bootstrap, y me gustaría elegir algunos enlaces de imagen de mi JSON que está ubicado en un servidor Apache2 y usarlos para renderizar esas imágenes en mi página principal. . También me gustaría deslizarlos como en un carrusel. Para hacer que funcione, estoy tratando de usar iDangero.us Swiper .

Cuando selecciono mis imágenes con 3 divisiones separadas, no tengo problemas. Obtengo mis imágenes y luego normalmente puedo deslizarlas como quiera. Lo hago como se muestra a continuación:

Main.html:

<div ng-init="initGetRequestMain()"> <div class="swiper-slide" ng-click="swipers()" style="{{data.background1}}"></div> <div class="swiper-slide" ng-click="swipers()" style="{{data.background2}}"></div> <div class="swiper-slide" ng-click="swipers()" style="{{data.background3}}"></div> <script src="scripts/custom/main/swipers.js"></script> </div>

Uso Swiper para pasar de una imagen a otra, y parece funcionar como debería. Es un plugin jQuery, y puedes ver algunas demos en este enlace .

Swipers.js:

angular.module(''swipers'', []) .controller('''',[ $(document).ready(function (){ var swiper = new Swiper(''.swiper-container'',{ direction: ''horizontal'', pagination: ''.swiper-pagination'', paginationClickable: true }) })]);

Json:

"background1":"background-image: url(images/img1.jpg)", "background2":"background-image: url(images/img2.jpg)", "background3":"background-image: url(images/img3.jpg)"

mainController.js:

myApp.controller(''MainController'', ["$scope","$http", function($scope,$http){ $scope.initGetRequestMain = function(){ $http.get(''http://localhost/main.json'').success(function(data){ $scope.data=data; }) } }]);

El problema es que cuando trato de usar ng-repeat lugar de 3 divs separados, no puedo verlos más y mi script Swiper se dispara antes de que estén completamente cargados. No tengo errores en mi consola o en mi JSON (validado con JSONLint). A continuación, agregué 2 capturas de pantalla de mi salida en ambas situaciones.

Trabajando con 3 divs separados:

No funciona con ng-repeat:

Este es el código donde trato de hacer que ng-repeat funcione manteniendo el mismo controlador y el mismo script de Swiper que antes:

Main.html:

<div ng-init="initGetRequestMain()"> <div ng-repeat="slide in data.slides" isLoaded=""> <div class="swiper-slide" style="{{slide.background}}" ng-click="swipers()"></div> </div> <script type="text/javascript-lazy" src="scripts/custom/main/swipers.js"></script> </div>

mainJson.json:

"slides":[ {"background":"background-image:url(''images/img1.jpg'')"}, {"background":"background-image:url(''images/img2.jpg'')"}, {"background":"background-image: url(''images/img3.jpg'')"} ],

Para cargar mis imágenes antes de activar el script, intento usar 2 directivas personalizadas.

isLoaded me dice cuándo se carga el último elemento ng-repeat y establece pageIsLoaded = true; :

myApp.directive(''isLoaded'', function (){ return{ scope:true, restrict: ''A'', //Attribute type link: function (scope, elements, arguments){ if (scope.$last === true) { scope.pageIsReady = true; console.log(''page Is Ready!''); } } } })

gettingTheScript espera para pageIsLoaded = true; y carga la secuencia de comandos:

myApp.directive(''src'', function (){ return{ scope:true, restrict: ''A'', //Attribute type link: function (scope, elements, arguments){ scope.$on(pageIsReady===true, function(){ if (attr.type === ''text/javascript-lazy''){ scope.scriptLink = arguments.src; } }) }, replace: true, //replaces our element template: ''{{scriptLink}}'' } })

No parecen arreglar mi problema. Tampoco puedo ver console.log(''page Is Ready!''); al hacer el primero.

Solo estoy teniendo problemas cuando tengo que activar un script como Swiper después de cargar la página para evitar este tipo de problemas. Mis imágenes parecen no tener altura. Creo que el problema se debe a que ng-repeat no se carga completamente antes de activar mi script.

¿Qué estoy haciendo mal? ¿Hay mejores soluciones?


Antes de entrar en cómo hacer que esto funcione, la mayoría de estos tipos de complementos jQuery no funcionan bien con angular ya que hacen modificaciones en el DOM que angular no conoce.

Una vez dicho esto, el truco es diferir la invocación del plugin jQuery hasta que Angular haya procesado el DOM.

Primero, ponga su plugin Swiper en una directiva:

.directive(''swiper'', function($timeout) { return { link: function(scope, element, attr) { //Option 1 - on ng-repeat change notification scope.$on(''content-changed'', function() { new Swiper(element , { direction: ''horizontal'', pagination: ''.swiper-pagination'', paginationClickable: true); } //Option 2 - using $timeout $timeout(function(){ new Swiper(element , { direction: ''horizontal'', pagination: ''.swiper-pagination'', paginationClickable: true); }); } }; })

Para la Opción 1, necesita una directiva isLoaded modificada

myApp.directive(''isLoaded'', function (){ return{ scope:false, //don''t need a new scope restrict: ''A'', //Attribute type link: function (scope, elements, arguments){ if (scope.$last) { scope.$emit(''content-changed''); console.log(''page Is Ready!''); } } } })

Finalmente, su marcado (tenga en cuenta que el cambio de isLoaded a is-loaded ... esta es probablemente la razón por la que no estaba viendo la notificación).

<div ng-init="initGetRequestMain()" swiper> <div ng-repeat="slide in data.slides" is-loaded> <div class="swiper-slide" style="{{slide.background}}" ng-click="swipers()"></div> </div> </div>

Como se mencionó, la mayoría de los complementos de jQuery que funcionan con carrusel no manejan los cambios al DOM (es decir, elementos nuevos) muy bien. Incluso con ambas opciones, puede ver cosas inesperadas si cambia su modelo después de que la repetición ng se represente por primera vez. Sin embargo, si su modelo es estático, esto debería funcionar para usted. Si su modelo cambia, entonces es posible que desee buscar una directiva de carrusel más "angular".


Estoy respondiendo a esta vieja pregunta porque algunos chicos me pidieron que lo haga y porque quiero ayudar a otros desarrolladores con este problema "divertido".

Después de más de un año, logré resolver este problema usando Promises y Factories .

Esencialmente, hice una Factory , ItemFactory asegurándome de obtener todos los elementos necesarios (en este caso, las diapositivas), luego, SwiperFactory otra Factory , SwiperFactory , que usa una Promise para activar ese chico divertido, swipers() . Llamé a todos esos métodos de fábrica en un MainController , que, después de obtener las diapositivas y activar el script, hace $scope.apply(); para reflejar los cambios en la vista principal.

Main.html:

//MainController known as mainCtrl <div ng-repeat="slide in mainCtrl.slides"> <div class="swiper-slide" ng-click="mainCtrl.swipers()"></div> </div>

MainController.js:

angular .module(''myApp'') .controller(''MainController'', MainController); function MainController($scope, ItemFactory, SwiperFactory) { var vm = this; //Initializing slides as an empty array vm.slides = []; /** Gets called as soon as the Controller is called **/ getData(''main.json''); function getData(path){ ItemFactory.getItems(path).then( function(response){ //If response is not empty if (response) { //Assigning fetched items to vm.items vm.slides = response.data; } //Calling triggerSwiper after we ensured fetching item data SwiperFactory.triggerSwiper(); //Callig $scope.$apply() to reflect correctly the changes in the view $scope.$apply(); }) }; }

ItemFactory.js:

angular .module(''myApp'') .factory(''ItemFactory'', function ($http) { /** Using this referring as ItemFactory Controller **/ var vm = this; vm.API_URL = ''http://localhost/''; /** Gets items from API based on jsonPath **/ function getItems(jsonPath) { return $http.get(vm.API_URL + jsonPath ).then(function (response) { return (response); }); } //Exposing getItems method return { getItems : getItems } });

SwiperFactory.js:

angular .module(''myApp'') .factory(''SwiperFactory'', function () { /** Using this referring as SwiperFactory Controller **/ var vm = this; /** Triggers Swiper Script * Resolving only after swiper has been triggered **/ function triggerSwiper(){ return new Promise( function(resolve, reject){ resolve({ $(document).ready(function (){ var swiper = new Swiper(''.swiper-container'',{ direction : ''horizontal'', pagination : ''.swiper-pagination'', paginationClickable : true }) }); }, function(error){ console.log(''Error while triggering Swiper''); }) } //Exposing triggerSwiper method return { triggerSwiper : triggerSwiper } });

  • $scope.$apply(); se puede eliminar, no es realmente esencial
  • En general, este tipo de enfoque funciona bien con tareas asincrónicas

El código anterior hace el trabajo, pero, por favor, preste atención a lo que digo a continuación

Intenta evitar el uso de bibliotecas jQuery como iDangero.us Swiper en un proyecto AngularJS. En su lugar, busque una biblioteca angular que haga el mismo trabajo. Si en aquel entonces tenía la destreza que tengo ahora mismo, nunca lo hubiera usado, especialmente por las $(document).ready . Cosas $(document).ready . En su lugar, estudie la manera de hacerlo de Promises o AngularJS. Era totalmente nuevo en AngularJS y Desarrollo web en general, así que tomé decisiones equivocadas.

Espero haber sido útil.


Hay una manera aún más fácil de usar que está incorporada en Swiper.js. Cuando está inicializando el conmutador, simplemente configure la propiedad del observador en verdadero. Esto hará que Swiper esté atento a los cambios en sus diapositivas, por lo que no tendrá que preocuparse de si se ejecuta antes de que todas las diapositivas se agreguen a través de ng-repeat.

Ejemplo:

var galleryTop = new Swiper(''.gallery-top'', { observer: true });

Y de la documentación de Swiper en la propiedad del observador:

Establézcalo en true para habilitar Mutation Observer en Swiper y sus elementos. En este caso, Swiper se actualizará (reiniciará) cada vez que cambie su estilo (como ocultar / mostrar) o modifique sus elementos secundarios (como agregar / eliminar diapositivas)