5

Ho implementato una direttiva di input personalizzata - counter con funzionalità di ripristino. La direttiva ha require: "ngModel".

Sto ripristinando lo stato di pristine della direttiva ngModel con $setPristine(). A differenza di $setDirty(), $setPristine() non tocca lo stato $pristine del modulo padre.

D: Come faccio a "Notifica" form padre che la presente direttiva non è più "sporco" è, in modo tale che il form padre potrebbe avere ripristinato il suo stato $pristine?

Tenere presente che chiamare semplicemente form.$setPristine() non è sufficiente in quanto potrebbero esistere altri controlli "sporchi" nel modulo, che la mia direttiva non dovrebbe (e non dovrebbe) conoscere.

Questa è funzione di collegamento della direttiva:

link: function(scope, element, attrs, ngModel){ 

    var original; 

    ngModel.$render = function(){ 
    original = scope.counter = ngModel.$viewValue; 
    }; 

    scope.up = function(){ 
    ngModel.$setViewValue(++scope.counter); 
    }; 

    scope.reset = function(){ 
    scope.counter = original; 
    ngModel.$setViewValue(scope.counter); 
    ngModel.$setPristine(); // this sets $pristine on the directive, but not the form 
    }; 
} 

Ed ecco come viene utilizzato:

<div ng-form="form"> 
    <counter ng-model="count"></counter> 
</div> 

plunker

+0

io non sono un esperto ma sei sicuro di pensarlo nel modo giusto? se hai bisogno di resettare il modulo dal tuo contatore forse dovresti includerlo nella direttiva? o il tuo contatore dovrebbe esporre una funzione da resettare e questo sarà chiamato dal reset del modulo? – MamaWalter

+0

Desidero solo notificare al modulo padre che questa direttiva non è più "sporca".La forma, idealmente, dovrebbe gestire il proprio stato sporco. I * potrebbe * anche 'richiedere:"^form "', ma cosa faccio allora? Non sono sicuro di aver compreso il secondo suggerimento di esporre una funzione per essere richiamata dal reset del modulo. –

+0

puoi mostrarci la tua intera dichiarazione direttiva. – levi

risposta

3

A partire dal 1.3.x angolare, non esiste una soluzione integrata.

form.$setPristine() imposta su tutti i controlli figlio. (link to code)

ngModel.$setPristine() imposta solo $ incontaminata su se stessa (link to code)

Un modo per risolvere questo è quello di creare una direttiva che vive accanto a una direttiva form e dirotta form.$setDirty per tenere traccia contare controlli sporchi. Questo è probabilmente il migliore in una fase di pre-collegamento (ad esempio prima che i controlli figlio inizino a registrarsi da soli).

app.directive("pristinableForm", function() { 
    return { 
    restrict: "A", 
    require: ["pristinableForm", "form"], 
    link: function(scope, element, attrs, ctrls) { 
     var me = ctrls[0], 
     form = ctrls[1]; 
     me.form = form; 
     me.dirtyCounter = 0; 
     var formSetDirtyFn = form.$setDirty; 
     form.$setDirty = function() { 
     me.dirtyCounter++; 
     formSetDirtyFn(); 
     }; 
    }, 
    controller: function() { 
     this.$notifyPristine = function() { 
     if (this.dirtyCounter === 0) return; 
     if (this.dirtyCounter === 1) { 
      this.dirtyCounter = 0; 
      if (this.form) this.form.$setPristine(); 
     } else { 
      this.dirtyCounter--; 
     } 
     }; 
    } 
    }; 
}); 

Quindi, la direttiva di ingresso personalizzato deve require: ["ngModel", "^pristinableForm"] e chiamare pristinableForm.$notifyPristine() nella sua funzione di reset:

scope.reset = function(){ 
    if (ngModel.$dirty){ 
    scope.counter = original; 
    ngModel.$setViewValue(scope.counter); 
    ngModel.$setPristine(); 
    pristinableForm.$notifyPristine(); 
    } 
}; 

L'utilizzo è:

<div ng-form="form" pristinable-form> 
    <counter ng-model="count1"></counter> 
    <counter ng-model="count2"></counter> 
    <input ng-model="foo" name="anotherControl"> 
</div> 

plunker

+0

Sembra un po 'troppo complesso per i miei gusti. Potete verificare la mia domanda relativa https://stackoverflow.com/questions/48528957/re-set-all-forms-to-pristine-status-from-the-bottom-up – Naomi

0

Questo è un non così buona soluzione. Scorrere i controlli collegati al modulo e verificare se ne esiste ancora uno sporco.

ho usato il metodo spiegare here per ottenere i controlli.

Plunker

app.directive("counter", function(){ 
    return { 
    require: "ngModel", 
    template: '<button ng-click="up()">{{counter}}</button><button ng-click="reset()">reset</button>', 
    link: function(scope, element, attrs, ngModel){ 

     var original; 

     ngModel.$render = function(){ 
     original = scope.counter = ngModel.$modelValue; 
     }; 

     scope.up = function(){ 
     ngModel.$setViewValue(++scope.counter); 
     }; 

     scope.reset = function(){ 
     scope.counter = original; 
     ngModel.$setViewValue(scope.counter); 
     ngModel.$setPristine(); 

     // check if one of the controls attached to the form is still dirty 
     var dirty = false; 
     angular.forEach(scope.form, function(val, key) { 
      if (key[0] != '$') { 
       if (val.$dirty) { 
       dirty = true; 
       } 
      } 
     }); 
     if(!dirty) scope.form.$setPristine(); 


     }; 
    } 
    }; 
}); 
+0

Grazie per l'aiuto, ma ho esplicitamente dichiarato che la sola chiamata '$ setPristine()' sul modulo non lo taglia, in quanto il modulo potrebbe avere altri controlli figlio che potrebbero essere sporchi. Inoltre, il modo migliore per farlo sarebbe quello di richiedere: "^ form" ', piuttosto che assumere che' scope.form' esista. –

+0

ok penso di aver capito, non sono sicuro che ci sia una soluzione integrata per questo. – MamaWalter

+0

ho modificato la mia risposta con una soluzione "sporca". – MamaWalter