javascript - Hvordan gjøre toveisfiltrering i AngularJS?
En av de interessante tingene AngularJS kan gjøre er å bruke et filter på et bestemt databindingsuttrykk, noe som er en praktisk måte å for eksempel bruke kulturspesifikk valuta- eller datoformattering på en models egenskaper. Det er også fint å ha beregnede egenskaper på scope. Problemet er at ingen av disse funksjonene fungerer med toveis databinding - kun envegs databinding fra scope til visning. Dette virker som en slående utelatelse i et ellers utmerket bibliotek - eller overser jeg noe?
I KnockoutJS kunne jeg opprette en les/skriv beregnet egenskap, som tillot meg å spesifisere et par funksjoner, en som kalles for å hente verdien av egenskapen, og en som kalles når egenskapen settes. Dette tillot meg å implementere for eksempel kulturbevisst input - la brukeren skrive "$1.24" og analysere det til et flyttall i ViewModel, og ha endringer i ViewModel reflektert i inputen.
Det nærmeste jeg kunne finne som ligner på dette, er bruken av $scope.$watch(propertyName, functionOrNGExpression); Dette lar meg få en funksjon kalt når en egenskap i $scope endres. Men dette løser ikke, for eksempel, problemet med kulturbevisst input. Merk problemene når jeg prøver å endre $watched-egenskapen innenfor selve $watch-metoden:
$scope.$watch("property", function (newValue, oldValue) {
$scope.outputMessage = "oldValue: " + oldValue + " newValue: " + newValue;
$scope.property = Globalize.parseFloat(newValue);
});
(http://jsfiddle.net/gyZH8/2/)
Inndatakomponenten blir veldig forvirret når brukeren begynner å skrive. Jeg forbedret det ved å dele egenskapen i to egenskaper, en for den uparsete verdien og en for den parseverdien:
$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/)
Dette var en forbedring i forhold til den første versjonen, men er litt mer omstendelig, og merk at det fortsatt er et problem med parsedValue-egenskapen til scope-endringene (skriv noe i det andre inputfeltet, som endrer parsedValue direkte. merk at det øverste inputfeltet ikke oppdateres). Dette kan skje fra en controller-handling eller ved lasting av data fra en datatjeneste.
Finnes det en enklere måte å implementere dette scenariet på ved bruk av AngularJS? Går jeg glipp av noen funksjonalitet i dokumentasjonen?
Svar #1
Det viser seg at det finnes en veldig elegant løsning på dette, men den er ikke godt dokumentert.
Formatering av modellverdier for visning kan håndteres av |-operatoren og en vinkel formatter. Det viser seg at ngModel ikke bare har en liste over formaterere, men også en liste over parser.
1. Bruk ng-model for å lage toveis datakobling
<input type="text" ng-model="foo.bar"></input>
2. Opprett en direktiv i Angular-modulen din som skal brukes på det samme elementet og som avhenger av ngModel-kontrolleren
module.directive('lowercase', function() {
return {
restrict: 'A',
require: 'ngModel',
link: function(scope, element, attr, ngModel) {
...
}
};
});
3. Inne i link-metoden, legg til dine egendefinerte konvertere til ngModel-kontrolleren
function fromUser(text) {
return (text || '').toUpperCase();
}
function toUser(text) {
return (text || '').toLowerCase();
}
ngModel.$parsers.push(fromUser);
ngModel.$formatters.push(toUser);
4. Legg til din nye direktiv til det samme elementet som allerede har ngModel
<input type="text" lowercase ng-model="foo.bar"></input>
Her er et fungerende eksempel som gjør tekst om til små bokstaver i input og tilbake til store bokstaver i modellen
API-dokumentasjonen for modellkontrolleren har også en kort forklaring og en oversikt over de andre tilgjengelige metodene.
