5

Piszę dyrektywę, która wymaga ngModel i dodaje formatery i parsery do manipulowania wartością. Działa świetnie, ale ponieważ manipulacja zależy od danych zewnętrznych, które muszę $ watch, szukam sposobu na aktualizację wartości modelu z tego zegarka. Próbowałem wywołać $setViewValue, ale nic się nie dzieje (ponieważ $ viewValue się nie zmieniło ??).

W następującym prostym przykładzie, zmiany `factor' nie aktualizuje wartość modelu

angular.module('app', []).directive('multiply', multiplyDirective); 
 

 
function multiplyDirective() { 
 
    return { 
 
     restrict: 'A', 
 
     require: 'ngModel', 
 
     scope: { 
 
      factor: '=multiply' 
 
     }, 
 
     link: function(scope, elem, attr, ngModel) { 
 

 
      ngModel.$formatters.push(function (value) { 
 
       return value/scope.factor; 
 
      }); 
 

 
      ngModel.$parsers.push(function (value) { 
 
       return value * scope.factor; 
 
      }); 
 

 
      scope.$watch('factor', function() { 
 
       // how to run the parsers pipeline to update modelvalue? 
 
       ngModel.$setViewValue(ngModel.$viewValue); 
 
      }); 
 
     } 
 
    } 
 
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.6/angular.min.js"></script> 
 

 

 
<body ng-app ng-init="factor = 1; value = 1"> 
 
    <input type="number" ng-model="value" multiply="factor" /> x 
 
    <input type="number" ng-model="factor" /> 
 
    = {{ value }} 
 
</body>

Edit: Działa jeśli zadzwonię wewnętrzna metoda $$parseAndValidate, ale Zastanawiam się, czy istnieje publiczny interfejs API do wymuszenia aktualizacji.

Edytuj: Rozgryzłem, że zachowanie ngModel.$setViewValue(ngModel.$viewValue); zmieniono w 1.3.0. Używanie kodu 1.2.x działa!

Odpowiedz

0

Twoja dyrektywa nie jest w ogóle załadowana. Musisz nadać nazwę modułu aplikacji ng, np. <body ng-app="app">. A potem wystarczy zadzwonić pod numer ngModel.$setViewValue(ngModel.$viewValue), gdy tylko czynnik zostanie zmodyfikowany.

angular.module('app', []).directive('multiply', multiplyDirective); 
 

 
function multiplyDirective() { 
 
    return { 
 
     restrict: 'A', 
 
     require: 'ngModel', 
 
     scope: { 
 
      factor: '=multiply' 
 
     }, 
 
     link: function(scope, elem, attr, ngModel) { 
 

 
      ngModel.$formatters.push(function (value) { 
 
       return value/scope.factor; 
 
      }); 
 

 
      ngModel.$parsers.push(function (value) { 
 
       return value * scope.factor 
 
      }); 
 

 
      scope.$watch('factor', function() { 
 
       // how to run the parsers pipeline to update modelvalue? 
 
       ngModel.$setViewValue(ngModel.$viewValue); 
 
       
 
      }); 
 
     } 
 
    } 
 
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script> 
 

 

 
<body ng-app="app" ng-init="factor = 1; value = 1"> 
 
    <input type="number" ng-model="value" multiply="factor" /> x 
 
    <input type="number" ng-model="factor" /> 
 
    = {{ value }} 
 
</body>

+0

Myślę, że "aplikacja" jest domyślnym argumentem ngApp, więc dyrektywa załadowała się. Ale zauważyłem, że zachowanie zmieniło się w wersji 1.3.0. Kod z $ setViewValue faktycznie działa w wersji 1.2.23, ale nie w wersji 1.3.0! – hansmaad

+0

Twój oryginalny wpis używa kątowego 1.2.23, z którym "aplikacja" nie jest domyślnym ngApp. Moja odpowiedź jest oparta na v1.2.23, więc czy mogę uzyskać "akceptowaną odpowiedź" lub głosowanie w górę? Po drugie, dla wersji 1.3.x "aplikacja" jest domyślnym ngApp. I najwyraźniej nieco zmieniono $ setViewValue. Mogę nie mieć pomysłu na ten temat, ale dlaczego nie po prostu utworzyć inną zmienną zakresu, aby zapisać obliczony wynik? Chyba że chcesz po prostu grać z 'ngModelController':> – elaijuh

+0

Tak, przepraszam za to. Nie spodziewałem się, że będzie to problem z wersją. Właśnie trzymałem wersję SO wstawioną do fragmentu.Ale nie mogę zaakceptować tej odpowiedzi, ponieważ nie rozwiązuje ona mojego prawdziwego problemu z 1.3.x. – hansmaad

0

źródeł v1.3.18, nie widzę publicznych API. Rurociąg idzie z $$ parseAndValidate metody, które nazywa się również z $ commitViewValue (trzeba popełnić/ustawić inną wartość lub że będzie return)

1

Odrobinę późno, ale opisałem w jaki sposób można to zrobić here. Działa to na AngularJS 1.6.x

Zasadniczo można wywołać $parsers pipeline za pomocą $setViewValue().

Poniżej znajduje się fragment kodu, który pozwala programowo ustawić NgModel na dowolny, przez "przejęcie" pipeline $ parsers. Odbywa się to za pomocą zamknięcia.

Skonfiguruj $ parser z zamknięciem tak:

const hijack = {trigger: false; model: null}; 
modelCtrl.$parsers.push(val => { 
    if (hijack.trigger){ 
     hijack.trigger = false; 
     return hijack.model; 
    } 
    else { 
     // .. do something else ... 
    }) 

Następnie na (re) tworzenie modelu potrzebne do uruchomienia rurociągu poprzez zmianę $viewValue z modelCtrl.$setViewValue('newViewValue'). (Tak, to prawda, że ​​nowa wartość widoku musi być inna w stosunku do bieżącej wartości).

const $setModelValue = function(model){ 
    // trigger the hijack and pass along your new model 
    hijack.trigger = true; 
    hijack.model = model; 
    // assuming you have some logic in getViewValue to output a viewValue string 
    modelCtrl.$setViewValue("some new view value"); 
    } 
Powiązane problemy