2014-04-08 22 views
13

Ich versuche, eine Paginierung Richtlinie mit AngularJS zu bauen 1.2.15:

Das ist meine Ansicht:

<input type="text" ng-model="filter.user"> 
<input type="number" ng-model="filter.limit" ng-init="filter.limit=5"> 
<ul> 
    <li ng-repeat="user in (filteredUsers = (users | orderBy:order:reverse | filter:filter.user) | limitTo: filter.limit)" ng-click="showDetails(user)"> 
    {{user.id}}/{{user.firstname}} {{user.lastname}} 
    </li> 
</ul> 
<div pagination data='filteredUsers' limit='filter.limit'></div> 

und hier ist meine Paginierung Richtlinie:

app.directive('pagination', function(){ 
    return { 
    restrict: 'A', 
    templateUrl: 'partials/pagination.html', 
    scope: { 
     data: '=data', 
     limit: '=limit' 
    } 
    } 
}) 

Alles funktioniert einwandfrei ohne die Paginierung Anweisung. Jedoch mit meiner neuen Direktive, sobald ich die Seite lade, bekomme ich einen $rootScope:infdig Fehler, den ich nicht verstehe, da die Direktive nichts tut, um Daten zu manipulieren, die in einer Endlosschleife landen könnten.
Was ist das Problem hier und wie kann ich es lösen? Vielen Dank!

Aktualisierung:
Hier sind der Controller und die Ressource.
Controller:

usersModule.controller('usersController', 
    function ($scope, Users) { 
    function init(){ 
     $scope.users = Users.get(); 
    } 
    init(); 
}) 

Ressource (bekommt Benutzer als ein Array aus einer REST API):

app.factory('Users', function($resource) { 
    return $resource('http://myrestapi.tld/users', null,{ 
     'get': { method:'GET', isArray: true, cache: true } 
    }); 
}); 

Update 2

Hier ist eine Demo: http://plnkr.co/edit/9GCE3Kzf21a7l10GFPmy?p=preview
Geben Sie einfach ein Buchstabe (zB "f") in den linken Eingang.

+0

Bitte geben Sie den Code für den Controller an, damit die Leute das Problem lösen können. Ich denke obige Richtlinie ist perfekt. Es kann Probleme mit Ihrem Controller geben. –

+0

einfache Client-Seite Paginierung - http://angulartutorial.blogspot.in/2014/03/client-side-pagination-using-angular-js.html – Prashobh

+0

@JenishRabadiya Ich habe den obigen Code aktualisiert. Allerdings glaube ich nicht, dass es etwas mit meinem Controller zu tun hat ... – Horen

Antwort

27

Das Problem liegt nicht innerhalb der Direktive, es ist innerhalb der $ watch die Direktive erstellt. Wenn Sie GefilterteBenutzer der Richtlinie zu senden, schafft die Richtlinie die folgende Zeile:

$scope.$watch("filteredUsers", function() { 
    // Directive Code... 
}); 

Beachten Sie im folgenden Beispiel, wie wir es ohne eine Richtlinie reproduzieren: http://plnkr.co/edit/uRj19PyXkvnLNyh5iY0j

Der Grund ist es passiert ist, weil Sie Die filteredUser werden jedes Mal geändert, wenn ein Digest ausgeführt wird (da Sie die Zuweisung in die ng-repeat-Anweisung geschrieben haben).

dies beheben Sie sich anschauen sollten beobachten und Filtern des Array in der Steuerung mit dem zusätzlichen Parameter ‚true‘ für die $ Uhr: http://plnkr.co/edit/stxqBtzLsGEXmsrv3Gp6

:

$scope.$watch("users | orderBy:order:reverse | filter:filter.user", function(newVal) { 
    $scope.filteredUsers = newVal; 
}, true); 

Sie die Lösung hier überprüfen Der $ watch ohne den zusätzlichen Parameter (true) führt einen einfachen Vergleich mit dem Objekt durch, und da Sie in jeder Digest-Schleife ein neues Array erstellen, ist das Objekt immer anders. Wenn Sie den True-Parameter an die $ watch-Funktion übergeben, bedeutet dies, dass er einen tiefen Vergleich mit dem Objekt vor dem erneuten Ausführen der $ watch durchführt, also selbst wenn Sie verschiedene Instanzen von Arrays mit denselben Daten haben wird sie als gleich betrachten.

+0

Ja, das scheint das Problem zu lösen. Ich verstehe nicht ganz, warum die '$ watch()' Funktion in Ihrem ersten Beispiel etwas ändert. Ich verstehe, dass es ausgelöst wird, wenn die Filter angewendet oder geändert werden. Die '$ watch()' -Funktion manipuliert oder ändert jedoch das "filteredUsers" -Objekt in keiner Weise. Wie wird eine Endlosschleife erzeugt? Selbst wenn die '$ watch()' Funktion ein neues Objekt mit jedem 'Digest' erzeugt, sollte sich dieses Objekt nicht ändern, richtig? Es wäre schön, wenn du das klären könntest - danke bis jetzt! – Horen

+0

Da Sie in Ihrer ng-repeat-Anweisung die Variable filteredUsers erstellen - Ihre Aussage lautet: filteredUsers = (Benutzer | orderBy: order: reverse | filter: filter.user), bedeutet dies, dass filteredUsers in jedem Digest-Zyklus eine neue Objektreferenz erhält . Wenn Sie die $ watch-Methode verwenden, überprüft es, ob die Referenz geändert wurde, und wenn dies der Fall ist, betrachtet es die Uhr als "schmutzig", führt die registrierte Rückrufmethode aus und führt die Digest-Schleife erneut aus - in der nächsten Digest-Schleife werden gefilterte Benutzer angezeigt ändere es erneut, damit der $ Watch Callback erneut aufgerufen wird - und hier ist deine Endlosschleife ... – Barnash

+0

Ok, danke. Warum reicht es jedoch nicht aus, das Objekt '$ scope.filteredUsers' in der Funktion' init() 'einmal zu deklarieren? Ich meine, dann sollte eckig wissen, dass es immer das gleiche Objekt ist, oder? – Horen

0

Eine schnelle Lösung ist ein "Handbuch" $watchCollection in der Direktive, anstelle einer 2-Wege-Bindung.

app.directive('pagination', function($parse){ 
    return { 
    restrict: 'A', 
    template: '', 
    scope: { 
     limit: '=limit' 
    }, 
    link: function(scope, elem, attrs) { 
     var dataExpr = $parse(attrs.data); 
     var deregister = scope.$parent.$watchCollection(dataExpr, function(val) { 
     scope.data = val; 
     }); 
     scope.$on('$destroy', deregister); 
    } 
    } 
}) 

$watchCollection überwacht die Inhalte des Arrays, nicht die Referenz darauf.

Sehen Sie es läuft here.

Generell Ich mag nicht Ausdrücke wie folgt aus:

filteredUsers = (users | orderBy:order:reverse | filter:filter.user) 

Innenansichten. Ansichten sollten nur $scope Eigenschaften rendern, keine neuen erstellen.

+0

Ich verstehe nicht, wie das mit dem isolierten Bereich funktioniert. Wie kann der isolierte Bereich den 'attrs.data'-Ausdruck korrekt auswerten? –

+0

@NicolaeSurdu, du hast Recht. Sie müssen die Überwachung im übergeordneten Bereich registrieren und die Registrierung aufheben, wenn der untergeordnete Bereich abbricht. Ich habe den Code bearbeitet. –

0

Dieser Fehler wird möglicherweise entfernt, um die Einstellung des Browserverlaufs zu löschen. Ich habe das gleiche Problem und viele Lösungen anwenden, um dies zu beheben, kann aber nicht lösen. Aber wenn ich Browserverlauf und Cache lösche, ist dieses Problem gelöst. Möge diese Hilfe für Sie sein.

Verwandte Themen