14

Ich mache eine Web-App mit AngularJS, jQuery, HTML, CSS und Bootstrap, und ich möchte einige Bild Links von meinem JSON, die in einem befindet Apache2 Server und verwende sie, um diese Bilder auf meiner Hauptseite zu rendern. Ich möchte sie auch gerne wie in einem Karussell wischen. Um das zu erreichen, versuche ich iDangero.us Swiper zu verwenden.jQuery Swiper-Skript zum Ausführen nach Ng-Repeat-Elemente geladen werden

Wenn ich meine Bilder mit 3 getrennten divs wähle, habe ich keine Probleme. Ich bekomme meine Bilder und dann kann ich sie normalerweise wischen, wie ich will. Ich mache es unten wie:

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> 

I swiper verwenden, um von einem Bild zum anderen zu streichen, und es scheint zu funktionieren, wie es sollte. Es ist ein jQuery-Plugin, und Sie können einige Demos unter this link sehen.

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; 
     }) 
     } 
    }]); 

Das Problem ist, wenn ich versuche, ng-repeat anstelle von 3 getrennten Divs zu verwenden, kann ich sie nicht mehr sehen und mein Swiper-Skript löst aus, bevor sie voll geladen sind. Ich habe keine Fehler in meiner Konsole oder in meinem JSON (validiert mit JSONLint). Im Folgenden habe ich zwei Screenshots meiner Ausgabe in beiden Situationen hinzugefügt.

Arbeiten mit 3 getrennt divs:

Working with 3 separated divs

Nicht mit ng-repeat arbeiten:

Not working with ng-repeat

Dies ist der Code, wo ich versuche ng-repeat Arbeit zu machen den gleichen Controller und das gleiche Swiper-Skript wie zuvor:

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')"} 
], 

Um meine Bilder vor dem Auslösen das Skript geladen werden, ich versuche 2 Gewohnheit zu verwenden Richtlinien.

isLoaded sagt mir, wenn das letzte ng-repeat Element geladen ist und setzt 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 wartet auf pageIsLoaded = true; und lädt das Skript:

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}}' 
     } 
    }) 

Sie scheinen nicht mein Problem zu beheben. Ich kann console.log('page Is Ready!'); auch nicht sehen, wenn ich das erste mache.

Ich habe nur einige Probleme, wenn ich ein Skript wie Swiper auslösen muss, nachdem die Seite geladen wurde, um diese Art von Problemen zu vermeiden. Meine Bilder scheinen keine Höhe zu haben. Ich denke, dass das Problem von ng-repeat nicht vollständig geladen wird, bevor Sie mein Skript auslösen.

Was mache ich falsch? Gibt es bessere Lösungen?

+0

Sie haben Richtlinie verwenden für diese –

+0

@KevalBhatt Können Sie das konkretisieren? Vielen Dank. – AndreaM16

+0

Wie Sie traurig, dass Ihr Skript ausgelöst wird, bevor sie geladen werden, so müssen Sie eine Direktive dafür schreiben und in der Anweisung $ timeout verwenden. Wenn Sie auf eckigen Seite arbeiten, dann für DOM-Manipulation immer Direktive verwenden, weil JavaScript zuerst dann Ihren anderen Code ausführen, so wie eckig weiß, dass Ihr JavaScript-Code einige Manipulation an Ihren Bildern tun wird –

Antwort

10

Bevor Sie sich mit der Funktionsweise dieser Funktion beschäftigen, funktionieren die meisten dieser jQuery-Plugins nicht gut mit eckigen, da sie Änderungen am DOM vornehmen, über die eckig nichts weiß.

Der Trick besteht darin, den Aufruf des jQuery-Plugins zu verschieben, bis Angular das DOM gerendert hat.

Zuerst setzen Sie Ihre swiper Plugin in eine Richtlinie:

.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); 
      }); 

     } 
    }; 
}) 

Für Option 1, benötigen Sie eine modifizierte isLoaded Richtlinie

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!'); 
     } 
    } 
    } 
}) 

Schließlich Markup (die Änderung von isLoaded zu beachten, ist, -geladen .... das ist wahrscheinlich der Grund, warum Sie die Benachrichtigung nicht sehen konnten).

<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> 

Wie bereits erwähnt, die meist jQuery-Plugins, die Karussell-Funktionalität zu tun behandelt keine Änderungen an den DOM (das heißt neue Elemente) sehr gut. Mit beiden Optionen können Sie unerwartete Dinge sehen, wenn Sie Ihr Modell ändern, nachdem der ng-repeat zuerst gerendert wurde. Wenn Ihr Modell jedoch statisch ist, sollte dies für Sie funktionieren. Wenn sich Ihr Modell ändert, sollten Sie nach einer mehr "eckigen" Karussell-Direktive suchen.

+0

Ihre Lösung scheint ziemlich gut zu sein. Ich gehe für die 1 ° Lösung. Ich versuche etwas wie [dies] (http://plnkr.co/edit/CSfLVWxy5vccTgtMZ9Er) (ofc der Plunk wird nicht funktionieren, ich kopiere nur etwas Code eingefügt, damit Sie es sehen), jetzt bin ich kann meine Bilder mit voller Breite sehen (gab Vater "swiper-wrapper" 100% 100%), aber das Skript scheint nicht zu funktionieren (aber es wurde korrekt importiert). Wie auch immer, ich importiere alle meine Scripts, aber Swiper in meiner index.html, ich importiere swipers.js in meiner Hauptdatei, wo es gebraucht wird. Irgendeine Idee? – AndreaM16

+0

Verschieben Sie den Import von swiper.js auf Ihre index.html-Seite. –

+0

Ich habe das schon versucht, aber nichts ändert sich. – AndreaM16

0

Ich beantworte diese alte Frage, weil einige Leute mich gebeten haben, es zu tun und weil ich anderen Entwicklern mit diesem "lustigen" Problem helfen möchte.

Nach mehr als einem Jahr konnte ich dieses Problem mit Promises und Factories lösen.

Im Grunde habe ich eine Factory, ItemFactory Gewährleistung der alle Einzelteile erhalten benötigt (in diesem Fall Folien), dann machte ich einen weiteren Factory, SwiperFactory, die verwendet ein Promise dass lustiger Typ auslösen, swipers(). Ich habe alle diese Factory-Methoden in eine MainController aufgerufen, die, nachdem ich die Folien erhalten und das Skript ausgelöst habe, $scope.apply(); die Änderungen in der Hauptansicht widerspiegelt.

Haupt.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:

  • $scope.$apply(); kann entfernt werden, ist es nicht wirklich wichtig,
  • In der Regel diese Art von Ansatz funktioniert gut mit asynchronen Aufgaben

Der obige Code ist die Arbeit, aber, bitte, zahlen Aufmerksamkeit auf das, was ich unten sage

Try avoiding using jQuery libraries such as iDangero.us Swiper in an AngularJS project. Instead, look for an Angular library which makes the same work. If back then I was skilled like I'm right now, I would have never used it, expecially for the $(document).ready stuff. Instead, study Promises or AngularJS way of doing that. I was totally new to AngularJS and Web Development in general, so I took wrong decisions.

Ich hoffe, ich war hilfreich.

3

Es gibt einen noch einfacheren Weg, den Sie verwenden können, der in Swiper.js gebacken wird. Wenn Sie den Swiper initialisieren, legen Sie einfach die observer-Eigenschaft auf true fest. Dadurch wird Swiper nach Änderungen an Ihren Folien Ausschau halten, so dass Sie sich keine Gedanken darüber machen müssen, ob es ausgeführt wird, bevor alle Folien durch ng-repeat hinzugefügt wurden.

Beispiel:

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

Und von der swiper Dokumentation auf der Beobachter Eigenschaft:

Set to true to enable Mutation Observer on Swiper and its elements. In this case Swiper will be updated (reinitialized) each time if you change its style (like hide/show) or modify its child elements (like adding/removing slides)

+0

Funktionierte nicht für mich ... Das war der Fehler: Uncaught TypeError: Fehler beim Ausführen von 'beobachten' auf 'MutationObserver': Parameter 1 ist nicht vom Typ 'Node'. - Ich war in der Lage, es zu debuggen, es scheint, dass in der 3804 die Variable "target" nicht definiert ist, der Beobachter kann die Beobachter zu den Kindknoten hinzufügen, aber er stoppt plötzlich nachdem er ein "undefined" gefunden hat - ich habe keine Ahnung warum das passiert. –

Verwandte Themen