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.

Relaterte artikler