2013-03-08 10 views
15

Dopo aver applicato orderBy nell'elenco delle caselle di input, se si modifica un campo, l'ordinamento inizia immediatamente e si perde lo stato attivo. Ho provato a scavare nel codice angolare e ho scoperto che hanno applicato qualcosa come $ watch sull'ordine, quindi gli attributi di ogni volta che il valore cambia ordina l'elenco. C'è un modo per disabilitare l'ordine durante l'editing? Non voglio lasciare l'ordine. Per ordinare i dati durante la modifica del testo. Qualsiasi aiuto sarà apprezzatoDisabilitare l'ordine in AngularJS durante la modifica dell'elenco

Here is my plunker

Nota: voglio usare orderBy & non hanno bisogno di alcuna alternativa come l'ordinamento della lista da qualsiasi controller stesso. Voglio solo l'ordine Per ordinare l'elenco una volta sul caricamento della pagina e poi rimanere tranquillo.

+1

Quando il server invia miei dati ce l'ho includono una colonna aggiuntiva 'sortby', che ha il campo (s) voglio il tipo da passare, poi ng-repeat usa che per l'orderBy. Questo campo non è nella modifica, quindi non cambia finché non ottengo di nuovo le file dal server. Cioè Quando "salvi" un record, i dati di ritorno vengono recuperati dal database, incluso sortBy, che sostituisce la stessa riga in $ scope, aggiornando quindi l'ordinamento sulla pagina solo dopo che la modifica è stata completata. –

risposta

8

È possibile sovrascrivere la direttiva per modificare il momento dell'aggiornamento nel momento in cui si desidera il riordino. Si potrebbe anche semplicemente non utilizzare ng-model e fare affidamento su un custom directive.

This thread discutere di sovrascrivere la direttiva di input per modificare l'aggiornamento del modello che deve essere attivato dall'evento tge blur. Dai uno sguardo allo fiddle.

Anche se si potrebbe ignorare la direttiva, non si deve fare questo, e la soluzione migliore, come spiegato ed esemplificato dal @Liviu T. nel comments below sarebbe quello di creare una direttiva personalizzata che elimina l'evento KeyUp vincolante e aggiunge una sfocatura uno . Ecco il codice di direttiva, e qui è Liviu's plunker:

app.directive('modelChangeBlur', function() { 
    return { 
     restrict: 'A', 
     require: 'ngModel', 
      link: function(scope, elm, attr, ngModelCtrl) { 
      if (attr.type === 'radio' || attr.type === 'checkbox') return; 

      elm.unbind('input').unbind('keydown').unbind('change'); 
      elm.bind('blur', function() { 
       scope.$apply(function() { 
        ngModelCtrl.$setViewValue(elm.val()); 
       });   
      }); 
     } 
    }; 
}); 
<input type="text" ng-model="variable" model-change-blur/> 

Purtroppo, come eventi angolari non sono spazi dei nomi, si dovrà rimuovere ogni caso precedentemente aggiunto.

+2

Vorrei suggerire di non ignorare, ma aggiungere una nuova direttiva che consente che il comportamento solo dove serve http://plnkr.co/edit/yoUmEUMMzecNlbKmtgDq?p=preview –

+0

buona soluzione, ma come suggerito nei commenti non dovremmo scavalcare quello già esistente. così come non voglio rompere nessun legame con la vista anche per un evento keydown –

+0

Accetto, e aggiorno la domanda per accogliere @LiviuT. soluzione. Sfortunatamente, l'unico modo per evitare l'aggiornamento 'keydown' è rimuovere eventi già associati all'elemento. Il punto di forza della soluzione di Liviu è che non perderai in altri momenti in cui viene utilizzata la direttiva predefinita. –

0

Non esiste un modo semplice o diretto per realizzare ciò che si desidera, ma ci sono alcune opzioni. Si dovrà lavorare senza ng-modello, e di utilizzare invece l'evento sfocatura:

JS:

var app = angular.module('myapp', []); 

app.controller('MainCtrl', function($scope) { 
    $scope.items = [ 
    { name: 'foo', id: 1, eligible: true }, 
    { name: 'bar', id: 2, eligible: false }, 
    { name: 'test', id: 3, eligible: true } 
    ]; 

    $scope.onBlur = function($event, item){ 
    // Here you find the target node in your 'items' array and update it with new value 
    _($scope.items).findWhere({id: item.id}).name = $event.currentTarget.value; 
    }; 
}); 

app.directive('ngBlur', function($parse) { 
    return function (scope, element, attr) { 
    var fn = $parse(attr.ngBlur); 
    element.bind('blur', function (event, arg) { 
     scope.$apply(function(){ 
     fn(scope, { 
      $event : event, 
      arg: arg 
     }); 
     }); 
    }); 
    }; 
}); 

HTML:

<div ng-controller="MainCtrl"> 
    <div ng-repeat="item in items | orderBy:'name'" > 
    <input value="{{item.name}}" ng-blur="onBlur($event, item)"/> 
    </div> 
</div> 

Plunker.

Ma essere consapevoli del fatto che ciò interromperà il legame bidirezionale tra il modello e la vista.

+0

ho un legame con altri elementi nella mia pagina e immagino che tali modifiche non verranno riflesse fino a quando non sfocato la casella di input. destra? non sarebbe più bello se potessimo semplicemente annullare/modificare l'ordine in modo tale da non vedere cambiamenti finché non ricarico la pagina o non applichi l'ordinamento tramite alcun pulsante. la tua soluzione è buona senza dubbio, ma non voglio hackerare con ng-model. spero che capisca –

+0

Il filtro 'orderBy' in realtà non sta guardando per le modifiche. È la direttiva ng-repeat che controlla la matrice 'items' e la reitera non appena viene modificato il modello ng. Quindi puoi andare come ho suggerito oppure puoi creare la tua direttiva ng-repeat personalizzata, che non guarderebbe le modifiche, ma invece sarebbe stata attivata da un altro (esplicito) modo. – Stewie

2

Seguendo @CaioToOn funziona ma si interrompe in Angular 1.2.4 (probabilmente l'intero ramo 1.2.X). Per farlo funzionare è necessario dichiarare la priorità della direttiva personalizzata come 1 (la direttiva di input è 0). La direttiva diventa allora:

app.directive('modelChangeBlur', function() { 
return { 
    restrict: 'A', 
    priority: 1, 
    require: 'ngModel', 
     link: function(scope, elm, attr, ngModelCtrl) { 
     if (attr.type === 'radio' || attr.type === 'checkbox') return; 

     elm.unbind('input').unbind('keydown').unbind('change'); 
     elm.bind('blur', function() { 
      scope.$apply(function() { 
       ngModelCtrl.$setViewValue(elm.val()); 
      });   
     }); 
    } 
}; 

});

Vedere http://plnkr.co/edit/rOIH7W5oRrijv46f4d9R?p=preview e https://stackoverflow.com/a/19961284/1196057 per la correzione di priorità correlata.

+0

questo è buono ma ho una casella di controllo nella griglia e quando un utente controlla l'oggetto, la riga si sposta verso la sua nuova posizione ordinata. Non sono sicuro di quello che posso fare al riguardo se non quello di annullare l'ordine per quello. –

10

Stavo usando orderBy in un elenco che potrebbe essere riordinato usando angular-sortable e si è verificato un problema simile.

La mia soluzione era di eseguire l'ordine manualmente, chiamando il filtro orderBy all'interno del controller quando la pagina è stata inizializzata e quindi richiamandola in seguito quando necessario, ad esempio in una funzione di richiamata dopo aver riordinato la lista.

+2

Puoi fornire un esempio per questo ... –

+3

C'è un esempio nella documentazione ufficiale: https://docs.angularjs.org/api/ng/filter/orderBy. Cerca 'var orderBy = $ filter ('orderBy');'. Non dimenticare di inserire '$ filter'. – Maxence

0

È possibile creare un filtro personalizzato e chiamarlo solo se necessario. Esempio quando si fa clic su 'Griglia di testa' per l'ordinamento o dopo aver aggiunto in modo dinamico/rimozione dei valori di matrice, o semplicemente clic di un pulsante (Aggiorna griglia)

È necessario alla dipendenza Inject angolare filtro e filtro sorta

angular 
    .module('MyModule') 
    .controller('MyController', ['filterFilter', '$filter', MyContFunc]) 

    function ExpenseSubmitter(funcAngularFilter, funcAngularFilterOrderBy) { 
     oCont = this; 
     oCont.ArrayOfData = [{ 
     name: 'RackBar', 
     age: 24 
     }, { 
     name: 'BamaO', 
     age: 48 
     }]; 
     oCont.sortOnColumn = 'age'; 
     oCont.orderBy = false; 
     var SearchObj = { 
     name: 'Bama' 
     }; 

     oCont.RefreshGrid = function() { 
     oCont.ArrayOfData = funcAngularFilter(oCont.ArrayOfData, SearchObj); 
     oCont.ArrayOfData = funcAngularFilterOrderBy('orderBy')(oCont.ArrayOfData, oCont.sortOnColumn, oCont.orderBy); 
    } 
} 

e chiamare in HTML qualcosa come:

<table> 
    <thead> 
    <tr> 
     <th ng-click="oCont.sortOnColumn = 'age'; oCont.RefreshGrid()">Age</th> 
     <th ng-click="oCont.sortOnColumn = 'name'; oCont.RefreshGrid()">Name</th> 
    </tr> 
    </thead> 
    <tbody> 
    <tr ng-repeat="val in oCont.ArrayOfData"> 
     <td>{{val.age}}</td> 
     <td>{{val.name}}</td> 
    </tr> 
    </tbody> 
</table> 
2

Un approccio diverso potrebbe essere quello di non concentrarsi sciolto per cominciare. Se il vostro problema principale è che il vostro perdere attenzione, allora invece di disattivazione orderBy, aggiungere questa direttiva per il vostro input:

app.directive("keepFocus", ['$timeout', function ($timeout) { 
    /* 
    Intended use: 
     <input keep-focus ng-model='someModel.value'></input> 
    */ 
    return { 
     restrict: 'A', 
     require: 'ngModel', 
     link: function ($scope, $element, attrs, ngModel) { 

      ngModel.$parsers.unshift(function (value) { 
       $timeout(function() { 
        $element[0].focus(); 
       }); 
       return value; 
      }); 

     } 
    }; 
}]) 

Poi basta:

<input keep-focus ng-model="item.name"/> 

So che questo non risponde direttamente si mette in discussione, ma potrebbe aiutare a risolvere il problema sottostante.

+0

Questo è stato utile e migliora la mia situazione, grazie. Tuttavia, se è presente una casella di controllo in un ordinamento e la si controlla, l'oggetto viene sparato nel suo giusto ordine. Qualche idea su come migliorarlo? –

0

È possibile bloccare l'ordine corrente mentre si sta modificando. Di 'la tua html si presenta così:

<tbody ng-repeat="item in items | orderBy:orderBy:reverse"> 
    <tr ng-click="startEdit()"> 
     <td>{{item.name}}</td> 
    </tr> 
</tbody> 

Nel vostro controller si scrive:

var savedOrderBy, savedReverse; 
$scope.startEdit() = function() { 
    $scope.items = $filter('orderBy')($scope.items, $scope.orderby, $scope.reverse); 

    for (var i = 0; i < $scope.items.length; ++i) { 
     if (i < 9999) { 
      $scope.items[i]['pos'] = ("000" + i).slice(-4); 
     } 
    } 

    savedOrderBy = $scope.orderBy; 
    savedReverse = $scope.reverse; 
    $scope.orderBy = 'pos'; 
    $scope.reverse = false; 
}; 

Prima che l'utente inizia a modificare, per prima cosa ordinare gli elementi attuali esattamente nello stesso ordine in cui attualmente compaiono nel pagina. Lo fai chiamando l'ordine da $ filtro() con i parametri di ordinamento correnti.

Quindi si passa sopra gli elementi - ora ordinati - e si aggiunge una proprietà arbitraria (qui "pos") e si imposta sulla posizione corrente. Io blocco zero in modo tale che la posizione 0002 si collochi prima di 0011. Forse non è necessario, non ne ho idea.

Normalmente si desidera ricordare l'ordine corrente, qui nelle variabili scope "savedOrder" e "savedReverse".

E infine dici angolare per ordinare con quella nuova proprietà "pos" e voilà l'ordine della tabella è bloccato, perché quella proprietà semplicemente non cambia durante la modifica.

Quando hai finito di modificare, devi fare il contrario. È ripristinare il vecchio ordinamento dalla variabili scope "savedOrder" e "savedReverse":

$scope.endEdit = function() { 
    $scope.orderBy = savedOrderBy; 
    $scope.reverse = reverse; 
}; 

Se l'ordine del $ scope.items questioni di array per voi, avrebbe anche per ordinare di nuovo al suo ordinamento originale .

0

Provare a utilizzare una variabile di ambito per modificare l'ordine. In questo caso, quando stai per ordinare, chiami una funzione nel controller che modifica il valore dell'ordine variabile nel campo che vuoi ordinare, e quando lo stai modificando, lo ripristini.

Esempio:

<li ng-repeat="item in filtered = (items | filter:search) | orderBy:order:rever" > 

Quindi qui abbiamo la variabile "ordine" a dire il ng-repeat dal quale campo la lista deve essere ordinato. Un pulsante chiama una funzione nel controller che modifica il valore "ordine".

<button type="button" id="orderName" click="changeOrder('item.name')" >Name order </button> 

<button type="button" id="orderDate" click="changeOrder('item.date')" >Date order </button>` 

E poi, nella funzione changeOrder

$scope.order = param; 

Dove 'param' è il campo che si desidera ordinare da. Se non fai niente altro, si sta andando ad avere lo stesso problema che aveva, così poi, dopo aver assegnato il valore corretto alla variabile ordine di andare

$scope.order = ""; 

che reimposta l'ordinamento. Il risultato è che l'ordine sarà efficace solo quando si preme il pulsante e quindi non si ordinerà di nuovo se non si preme di nuovo il pulsante. Questo può essere cambiato in modo che ordini di nuovo quando, ad esempio, hai finito di modificare un elemento, come volevi.

Problemi correlati