2014-12-04 7 views
6

Sto cercando di implementare una griglia in angolare, utilizzando l'ordinamento lato server, l'impaginazione lato server e il filtro lato server. Usando ui-grid (unstable), ho aggiunto ui.grid.paging e ho ottenuto tutto funzionante. Molto bello, complimenti agli sviluppatori.filtro ui-griglia angolare/ng-griglia. Frequenza di sparo troppo frequente

Tuttavia .... $ scope.gridApi.core.on.filterChanged sta sparando per ogni tasto premuto, così quando ho ricerca di "Patrick" nella colonna givenname, sette eventi vengono generati e sette get-richieste ha colpito il mio server. Ancora peggio, dal momento che si tratta di un grande set che sto filtrando, questa operazione è piuttosto costosa ei miei risultati si superano a vicenda, come il filtro più specifico che ottiene il risultato più veloce, innescando il successo prima che venga elaborato un risultato meno specifico.

Mi piacerebbe rallentarlo, come "l'incendio dopo l'ingresso si è fermato". Sono praticamente nuovo per javascript e REST, questo è il mio primo vero progetto-mondo. Gradirei davvero qualche idea su come gestire questo problema. Sembra uno scenario comune, quindi potrebbero mancare alcune soluzioni standard o le migliori pratiche.

Cordiali saluti, Patrick.

risposta

16

Se si vuole andare "all angolare" Vorrei suggerire a utilizzare un $timeout all'interno del gestore on.filterChanged eventi:

if (angular.isDefined($scope.filterTimeout)) { 
    $timeout.cancel($scope.filterTimeout); 
} 
$scope.filterTimeout = $timeout(function() { 
    getPage(); 
}, 500); 

dove 500 è il tempo (in millisecondi) che si desidera attendere tra un evento on.filterChanged prima di andare al server e getPage() è la funzione che in realtà va al server e recupera i dati.

Non dimenticare di cancellare il tuo $timeout sul controller 'distruggere' evento:

$scope.$on("$destroy", function (event) { 
    if (angular.isDefined($scope.filterTimeout)) { 
     $timeout.cancel($scope.filterTimeout); 
    } 
}); 
0

Si consiglia di dare un'occhiata a reactive-extensions for Javascript. Reattivo è costruito proprio per questo tipo di scenari. Esiste un metodo chiamato .Throttle (millisecondi) che puoi allegare a un osservabile che chiamerà un gestore (per colpire la tua API) dopo che sono passati x millisecondi perché l'utente non abbia inserito nulla.

Rx-Js and angular play well together

Ecco un esempio di uno dei miei progetti di fare qualcosa di simile:

observeOnScope($scope, 'tag', true) 
      .throttle(1000) 
      .subscribe(function (data) { 
       if (data.newValue) { 
        $http({ 
         url: api.endpoint + 'tag/find', 
         method: 'GET', 
         params: {text: data.newValue} 
        }).then(function (result) { 
         $scope.candidateTags = result.data; 
        }) 
       } 
      }); 

Questo codice prende $scope.tag e lo trasforma in un osservabile. Il .throttle(1000) significa che dopo 1 secondo di $scope.tag non si modifica la funzione di iscrizione, verrà chiamato dove (dati) è il nuovo valore. Dopodiché puoi colpire la tua API.

Ho usato questo per fare ricerca typeahead dei valori dalla mia API in modo da colpire il backend ogni volta una lettera cambiata, ovviamente, non era il modo di andare :)

+0

Ho implementato la soluzione "tutto angolare", poiché non implica dipendenze esterne. Tuttavia, le tue soluzioni sembrano molto interessanti e le darò presto un'occhiata. – user3700169

8

avevo a che fare con lo stesso problema e mi si avvicinò con un'altra soluzione, che secondo me è più "Angular-friendly" . Ho utilizzato lo ngModelOptions directive introdotto in Angular 1.3. Ho sostituito il modello di filtro predefinito di uiGrid ("ui-grid/ui-grid-filter") da uno personalizzato e ho configurato la direttiva ngModelOptions sull'input con un valore di debounce predefinito di 300 ms e 0 ms per l'offuscamento.

Questo è un modello di esempio basato su ui-grid 3.0.5 modello originale, dove ho anche cambiato classi CSS predefiniti per classi Bootstrap:

$templateCache.put('ui-grid/ui-grid-filter-custom', 
    "<div class=\"ui-grid-filter-container\" ng-repeat=\"colFilter in col.filters\" ng-class=\"{'ui-grid-filter-cancel-button-hidden' : colFilter.disableCancelFilterButton === true }\">" + 
    "<div ng-if=\"colFilter.type !== 'select'\"><input type=\"text\" class=\"input-sm form-control\" ng-model=\"colFilter.term\" ng-model-options=\"{ debounce : { 'default' : 300, 'blur' : 0 }}\" ng-attr-placeholder=\"{{colFilter.placeholder || ''}}\" aria-label=\"{{colFilter.ariaLabel || aria.defaultFilterLabel}}\"><div role=\"button\" class=\"ui-grid-filter-button\" ng-click=\"removeFilter(colFilter, $index)\" ng-if=\"!colFilter.disableCancelFilterButton\" ng-disabled=\"colFilter.term === undefined || colFilter.term === null || colFilter.term === ''\" ng-show=\"colFilter.term !== undefined && colFilter.term !== null && colFilter.term !== ''\"><i class=\"ui-grid-icon-cancel\" ui-grid-one-bind-aria-label=\"aria.removeFilter\">&nbsp;</i></div></div>" + 
    "<div ng-if=\"colFilter.type === 'select'\"><select class=\"form-control input-sm\" ng-model=\"colFilter.term\" ng-attr-placeholder=\"{{colFilter.placeholder || aria.defaultFilterLabel}}\" aria-label=\"{{colFilter.ariaLabel || ''}}\" ng-options=\"option.value as option.label for option in colFilter.selectOptions\"><option value=\"\"></option></select><div role=\"button\" class=\"ui-grid-filter-button-select\" ng-click=\"removeFilter(colFilter, $index)\" ng-if=\"!colFilter.disableCancelFilterButton\" ng-disabled=\"colFilter.term === undefined || colFilter.term === null || colFilter.term === ''\" ng-show=\"colFilter.term !== undefined && colFilter.term != null\"><i class=\"ui-grid-icon-cancel\" ui-grid-one-bind-aria-label=\"aria.removeFilter\">&nbsp;</i></div></div>" + 
    "</div>" 
); 

Il passo finale per questo lavoro è quello di impostare questo modello in tutti i columnDef in cui si attiva il filtraggio:

columnDefs: [{ 
    name: 'theName', 
    displayName: 'Whatever', 
    filterHeaderTemplate: 'ui-grid/ui-grid-filter-custom' 
}] 

Purtroppo, Non ho trovato alcun modo per definire questo modello a livello globale, quindi ho dovuto ripetere filterHeaderTemplate ovunque ... Questo è l'unico inconveniente, ma d'altra parte, se lo desideri, puoi anche aggiungere più filtri al tuo modello personalizzato.

Spero che aiuti!

+1

Questa è in realtà la migliore risposta. – uksz

+0

soluzione impressionante. Grazie – WeMakeSoftware

+1

In realtà se si imposta l'override in app.run con $ templateCache.put ('ui-grid/ui-grid-filter', ...); allora questo dovrebbe scavalcare la definizione predefinita da ui-grid. – anre

0

JavaScript setTimeout La funzione può essere utilizzata anche per dare un ritardo come indicato di seguito.

$scope.gridApi.core.on.filterChanged($scope, function() { 

    if (angular.isDefined($scope.filterTimeout)) { 
     clearTimeout($scope.filterTimeout); 
    } 
    $scope.filterTimeout = setTimeout(function(){ 
     getPage(); 
    },1000); 

});