Come fare il filtro bidirezionale in AngularJS?

Una delle cose interessanti che AngularJS può fare è applicare un filtro a una particolare espressione di associazione dati, che è un modo conveniente per applicare, ad esempio, la valuta specifica della cultura o la formattazione della data delle proprietà di un modello. È anche bello avere proprietà calcolate sull’oscilloscopio. Il problema è che nessuna di queste funzionalità funziona con gli scenari di associazione dati bidirezionale, solo l’associazione dati unidirezionale dall’ambito alla vista. Questa sembra essere un’omissione evidente in una biblioteca altrimenti eccellente – o mi manchi qualcosa?

In KnockoutJS , potevo creare una proprietà calcasting in lettura / scrittura, che mi permetteva di specificare una coppia di funzioni, una che viene chiamata per ottenere il valore della proprietà e una che viene chiamata quando viene impostata la proprietà. Ciò mi ha permesso di implementare, ad esempio, l’input compatibile con la cultura, consentendo all’utente di digitare “$ 1,24” e analizzarlo in un float nel ViewModel, e avere modifiche nel ViewModel riflesse nell’input.

La cosa più vicina che potrei trovare simile a questo è l’uso di $scope.$watch(propertyName, functionOrNGExpression); Questo mi permette di avere una funzione invocata quando cambia una proprietà in $scope . Ma questo non risolve, ad esempio, il problema dell’input della cultura. Osserva i problemi quando provo a modificare la proprietà $watched all’interno del metodo $watch stesso:

 $scope.$watch("property", function (newValue, oldValue) { $scope.outputMessage = "oldValue: " + oldValue + " newValue: " + newValue; $scope.property = Globalize.parseFloat(newValue); }); 

( http://jsfiddle.net/gyZH8/2/ )

L’elemento di input diventa molto confuso quando l’utente inizia a digitare. L’ho migliorato dividendo la proprietà in due proprietà, una per il valore unparsed e una per il valore analizzato:

 $scope.visibleProperty= 0.0; $scope.hiddenProperty = 0.0; $scope.$watch("visibleProperty", function (newValue, oldValue) { $scope.outputMessage = "oldValue: " + oldValue + " newValue: " + newValue; $scope.hiddenProperty = Globalize.parseFloat(newValue); }); 

( http://jsfiddle.net/XkPNv/1/ )

Questo è stato un miglioramento rispetto alla prima versione, ma è un po ‘più prolisso e si noti che c’è ancora un problema nella proprietà parsedValue delle modifiche dell’ambito (digitare qualcosa nel secondo input, che modifica direttamente il parsedValue . non si aggiorna). Ciò potrebbe accadere da un’azione del controller o dal caricamento di dati da un servizio dati.

C’è un modo più semplice per implementare questo scenario usando AngularJS? Mi manca qualche funzionalità nella documentazione?

Solutions Collecting From Web of "Come fare il filtro bidirezionale in AngularJS?"

Si scopre che c’è una soluzione molto elegante a questo, ma non è ben documentata.

La formattazione dei valori del modello per la visualizzazione può essere gestita da | operatore e un formatter angular. Si scopre che il ngModel che ha non solo un elenco di formattatori ma anche un elenco di parser.

1. Utilizzare ng-model per creare l’associazione dati bidirezionale

  

2. Creare una direttiva nel modulo angular che verrà applicata allo stesso elemento e che dipende dal controller ngModel

 module.directive('lowercase', function() { return { restrict: 'A', require: 'ngModel', link: function(scope, element, attr, ngModel) { ... } }; }); 

3. All’interno del metodo di link , aggiungere i convertitori personalizzati al controller ngModel

 function fromUser(text) { return (text || '').toUpperCase(); } function toUser(text) { return (text || '').toLowerCase(); } ngModel.$parsers.push(fromUser); ngModel.$formatters.push(toUser); 

4. Aggiungi la tua nuova direttiva allo stesso elemento che ha già il ngModel

  

Ecco un esempio funzionante che trasforma il testo in minuscolo input e torna in maiuscolo nel modello

La documentazione API per il controller del modello ha anche una breve spiegazione e una panoramica degli altri metodi disponibili.