2014-04-08 21 views
13

Sto cercando di costruire una direttiva impaginazione con angularjs 1.2.15:

Questa è la mia opinione:

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

ed ecco la mia direttiva impaginazione:

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

Tutto funziona perfettamente senza la direttiva di impaginazione. Tuttavia con la mia nuova direttiva non appena carico la pagina ottengo un errore che non capisco dato che la direttiva non sta facendo nulla per manipolare i dati che potrebbero finire in un ciclo infinito.
Qual è il problema qui e come posso risolverlo? Grazie!

Aggiornamento:
Ecco il controller e la risorsa.
Controller:

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

Resource (ottiene utenti come una matrice da un API REST):

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

Update 2

Ecco una demo: http://plnkr.co/edit/9GCE3Kzf21a7l10GFPmy?p=preview
basta digitare una lettera (es. "f") nell'input sinistro.

+0

Specificare il codice per il controller in modo che le persone possano raggiungere il problema. Penso che la direttiva sopra sia perfetta. Ci possono essere problemi con il tuo controller. –

+0

paginazione lato client semplice - http://angulartutorial.blogspot.in/2014/03/client-side-pagination-using-angular-js.html – Prashobh

+0

@JenishRabadiya Ho aggiornato il codice sopra. Tuttavia, non penso che abbia nulla a che fare con il mio controller ... – Horen

risposta

27

Il problema non è all'interno della direttiva, è all'interno del $ watch che la direttiva crea. Quando si invia filteredUsers alla direttiva, la direttiva crea la seguente riga:

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

Avviso nel seguente esempio di come riproduciamo senza una direttiva: http://plnkr.co/edit/uRj19PyXkvnLNyh5iY0j

La ragione per cui accade è perché tu sei cambiando gli utenti filtrati ogni volta che viene eseguito un digest (poiché l'assegnazione viene assegnata all'istruzione ng-repeat).

Per correggere questo si potrebbe considerare di guardare e filtrando l'array nel controller con il parametro in più 'vera' per il $ orologio:

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

È possibile controllare la soluzione qui: http://plnkr.co/edit/stxqBtzLsGEXmsrv3Gp6

il $ watch senza il parametro extra (true) farà un semplice confronto con l'oggetto, e dal momento che si crea un nuovo array in ogni ciclo di digest, l'oggetto sarà sempre diverso. Quando si passa il parametro true alla funzione $ watch, significa che eseguirà effettivamente un confronto approfondito con l'oggetto restituito prima di eseguire nuovamente $ watch, quindi anche se si hanno istanze diverse di array che hanno gli stessi dati li considererà uguali.

+0

Sì, sembra che risolva il problema. Non capisco del tutto perché la funzione '$ watch()' nel tuo primo esempio cambi qualcosa, comunque. Capisco che sia attivato quando i filtri vengono applicati o modificati. Tuttavia la funzione '$ watch()' non manipola o modifica l'oggetto 'filteredUsers' in alcun modo. Quindi come viene generato un ciclo infinito? Anche se la funzione '$ watch()' crea un nuovo oggetto con ogni 'digest' questo oggetto non dovrebbe cambiare, giusto? Sarebbe bello se tu potessi chiarire - grazie finora! – Horen

+0

Dal momento che nella tua dichiarazione di ripetizione ng si crea la variabile Usered filter - La tua istruzione è: filteredUsers = (users | orderBy: order: reverse | filter: filter.user), significa che in ogni ciclo di digest, gli utenti filtrati ottengono un nuovo oggetto di riferimento . Quando usi il metodo $ watch, controlla se il riferimento è cambiato e se lo ha, considera l'orologio "sporco", esegue il metodo di callback registrato su di esso e quindi esegue di nuovo il ciclo digest - nel prossimo ciclo del digest filtratoUtilizzatori cambia di nuovo, quindi la richiamata di $ watch sarà richiamata di nuovo - ed ecco il tuo ciclo infinito ... – Barnash

+0

Ok, grazie. Perché tuttavia non è sufficiente dichiarare l'oggetto '$ scope.filteredUsers' nella funzione' init() 'una volta? Voglio dire, allora l'angolare dovrebbe sapere che è sempre lo stesso oggetto, giusto? – Horen

0

Una soluzione rapida consiste nell'aggiungere un "manuale" $watchCollection nella direttiva, anziché in un collegamento a 2 vie.

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 monitor i contenuti della matrice, non il riferimento ad esso.

Vedere in esecuzione here.

In generale, non mi piace che espressioni come:

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

viste all'interno. Le viste dovrebbero solo rendere le proprietà $scope, non crearne di nuove.

+0

Non capisco come funzioni con lo scope isolato. Come sarà lo scope isolato essere in grado di valutare correttamente l'espressione 'attrs.data'? –

+0

@NicolaeSurdu, hai ragione. È necessario registrare l'orologio sull'ambito principale e annullare la registrazione quando l'oscilloscopio secondario muore. Ho modificato il codice. –

0

Questo errore può essere rimosso per cancellare la cronologia del browser dalle impostazioni. Ho avuto lo stesso problema e ho applicato molte soluzioni per risolvere questo problema, ma non posso risolvere. Ma quando rimuovo la cronologia del browser e cache questo problema è risolto. Possa questo aiuto per te.

Problemi correlati