2013-04-09 15 views
29

Provo a creare una direttiva che dovrebbe eseguire alcune azioni quando un campo di input è contrassegnato come non valido. Per questo esempio permette di assumere ho una direttiva che controlla se l'ingresso è un numero primo, e io voglio creare una direttiva che aggiunge una classe all'elemento quando è valida:validità vigilanza direttiva AngularJS

<input type="text" ng-model="primeNumber" validate-prime invalid-add-class="error"> 

Il validate-prime utilizza la parser e formattatori su ng-model per aggiornare la validità del modello.

Ora desidero che la direttiva invalid-add-class aggiunga la classe "error" quando il modello non è valido e rimuoverlo quando è valido. In altre parole, dovrebbe guardare la proprietà $ valida (o $ non valida) del controller del modello. Tuttavia, non riesco a capire come farlo funzionare. Ho provato:

link : function(scope, element, attrs, ctrl) { 
    ctrl.$watch("$valid", function(newVal, oldVal) { 
    //never fired 
    }); 
} 

Forse potrei guardare un po 'variabile sul campo di applicazione, ma non so quale variabile da controllare.

Quindi, come posso ricevere una notifica quando cambia la validità di un modello?

+0

se puoi condividere la tua direttiva sarà bello! –

+0

Non ricordo per cosa ho usato esattamente questo, ma la seconda soluzione di CaioToOn è praticamente l'intera funzione di collegamento. Solo il corpo della seconda funzione dovrebbe essere riempito con qualsiasi azione tu voglia quando la validità cambia. – Tiddo

risposta

60

Se si dispone di un <form>, aggiungere un name ad esso (lascia supporre 'myForm') e una name al vostro ingresso (lascia supporre myInput). Si dovrebbe essere in grado di $watch questo:

scope.$watch('myForm.myInput.$valid', function(validity) {}) 

Se non si dispone di un form, si può sempre guardare una funzione. In questo modo:

scope.$watch(function() { return ctrl.$valid; }, function(validity){}); 

Si può leggere di più l'approccio modulo here.

+1

Il tuo secondo approccio lo ha fatto per me, grazie! – Tiddo

7

Il nostro obiettivo, in generale, dovrebbe essere quello di far funzionare una direttiva indipendentemente da qualsiasi forma o input. Come possiamo consentirci di leggere la proprietà locale $valid senza vincolarla obbligatoriamente a un singolo modulo specifico nome dell'input &?

Basta usare require: 'ngModel' come una delle proprietà della configurazione della direttiva. Ciò inietterà il controller ngModel locale come quarto argomento della funzione di collegamento, e puoi posizionare uno $watch direttamente su $valid senza dover accoppiare l'implementazione della direttiva a nessun particolare modulo o input.

require: 'ngModel', 
link: function postLink(scope, element, attrs, controller) { 
    scope.inputCtrl = controller; 
    scope.$watch('inputCtrl.$valid', handlerFunc) 
} 

Il gestore deve costantemente attivare le modifiche a $ valido con quella struttura. Vedere this Fiddle, in cui l'input è convalidato per il modello di un codice postale degli Stati Uniti o Zip + 4. Riceverai un avviso ogni volta che cambia la validità.

EDIT 21/3/14: questo post in precedenza mi ha bloccato su un mio delirio, fissando la causa sbagliata di un problema di implementazione. Colpa mia. L'esempio sopra rimuove quella fissazione. Inoltre, ha aggiunto il violino, dimostrando che questo approccio in effetti funziona, e lo ha sempre fatto, dopo aver aggiunto le virgolette attorno all'espressione dell'orologio.

+0

Sei sicuro che funzioni? Perché a me sembra che 'inputCtrl. $ Valid' sarebbe valutato una volta (quando viene eseguita la funzione link) e che il risultato è passato a' scope. $ Watch'. Ciò significherebbe che la chiamata effettiva potrebbe essere 'scope. $ Watch (true, handlerFunc)' o 'scope. $ Watch (false, handlerFunc)', entrambi i quali non danno luogo a una variabile vista. – Tiddo

+0

'inputCtrl. $ Valid' è un riferimento a una proprietà di un oggetto, non a un valore primitivo. Sarà valutato come tale ogni volta che il '$ watch' scatta. Ho lavorato su progetti personali, ma al momento non ho una buona demo pubblica disponibile. – XML

+1

AFAIK 'inputCtrl. $ Valid' È un primitivo. È "true", "false" o "undefined", che sono tutti primitivi. Non è possibile creare riferimenti alle proprietà degli oggetti, ma solo agli oggetti stessi in Javascript. Vedi anche questo JSFiddle: http://jsfiddle.net/9Mh92/2/. Come puoi vedere, il tuo codice non attiva la richiamata, ma solo con le virgolette. Questo è di nuovo perché non puoi creare un riferimento a nessun primitivo. Inserendo virgolette su 'inputCtrl. $ Valid' si istruisce l'angolazione per valutare quell'espressione nello scope corrente, e quindi funziona. – Tiddo

12

Se non si dispone di un <form /> si può facilmente ottenere uno:

nella definizione direttiva:

require: '^form' 

e poi nella vostra funzione di collegamento, il modulo viene passato come il quarto parametro:

link: function (scope, element, attr, ctrl) { 

Ora non c'è bisogno di hard-code il modulo o il campo di input per eseguire l'orologio $:

scope.$watch(ctrl.$name + '.' + element.attr('name') + '.$valid', 
function (validity) {}); 
+0

Questo è stato perfetto. Sebbene per qualche ragione dovessi usare 'ctrl [0]. $ Name' - non sono sicuro del motivo per cui il mio controllo stava restituendo un array di 1 modulo sebbene ... – DoubleA

+1

restituirà un array se l'attributo 'require' è passato ad un array (Sospetto che sia per te) – pixelbits

Problemi correlati