5

Sto scrivendo una direttiva che richiede ngModel e aggiunge formattatori e parser per manipolare il valore. Funziona alla grande, ma dal momento che la manipolazione dipende da dati esterni che devo guardare, sto cercando un modo per aggiornare il valore del modello da questo orologio. Ho provato a chiamare $setViewValue ma non succede nulla (perché $ viewValue non è cambiato ??).

Nel seguente semplice esempio, le modifiche a `factor' non si aggiorna il valore del modello:

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: Funziona se io chiamo il $$parseAndValidate metodo interno, ma io mi chiedo se ci sia un'API pubblica per far rispettare l'aggiornamento.

Modifica: ho capito che il comportamento di ngModel.$setViewValue(ngModel.$viewValue); è stato modificato in 1.3.0. Utilizzando 1.2.x il codice funziona!

risposta

0

La vostra direttiva non è stata caricata affatto. Devi dare il nome del modulo a ng-app come <body ng-app="app">. E dopo basta chiamare lo ngModel.$setViewValue(ngModel.$viewValue) ogni volta che il fattore viene modificato.

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

Penso che "app" sia l'argomento ngApp predefinito, quindi la direttiva è stata caricata. Ma ho notato che il comportamento è cambiato in 1.3.0. Il codice con $ setViewValue funziona in realtà in 1.2.23 ma non in 1.3.0! – hansmaad

+0

Il tuo post originale utilizza la versione 1.2.23 angolare con la quale 'app' non è la ngApp predefinita. La mia risposta è basata solo sulla v1.2.23, quindi posso guadagnare una "risposta accettata" o un voto positivo? In secondo luogo, per 1.3.x, 'app' è la ngApp predefinita. E apparentemente $ setViewValue è leggermente cambiato. Potrei non avere un'idea su questo, ma perché non creare solo un'altra variabile di ambito per memorizzare il risultato calcolato? A meno che non vogliate giocare con 'ngModelController':> – elaijuh

+0

Sì, mi dispiace per quello. Non mi aspettavo che questo fosse un problema di versione. Ho semplicemente mantenuto la versione SO inserita nello snippet.Ma non posso accettare questa risposta, perché non risolve il mio problema reale che ho con 1.3.x. – hansmaad

0

da fonti di v1.3.18, non vedo API pubblica. L'oleodotto va da $$ parseAndValidate metodo, che è anche chiamato da $ commitViewValue (necessità di impegnare/set valore diverso o lo farà return)

1

Un po 'in ritardo, ma ho descritto come si può fare questo here. Funziona su AngularJS 1.6.x

Fondamentalmente è possibile attivare lo utilizzando $setViewValue().

Di seguito è riportato uno snippet di codice che consente di impostare in modo programmatico ngModel su qualsiasi valore desiderato, "sequestrando" la pipeline $ parsers. Questo viene fatto usando una chiusura.

Impostare un $ parser con una chiusura in questo modo:

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

Poi, per (ri) impostando il modello è necessario per attivare il gasdotto cambiando il $viewValue con modelCtrl.$setViewValue('newViewValue'). (Sì, è vero che il nuovo valore di visualizzazione deve essere diverso rispetto al valore corrente).

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"); 
    }