2016-08-05 4 views
0

Ich versuche Angulars ngMessages eine benutzerdefinierte Validierungsfunktion hinzuzufügen.Angular ngMessages - Zugriff auf mehrere Formularwerte

Insbesondere möchte ich den Wert von ein paar Eingänge (die Anzahl der Eingänge wird dynamisch sein, aber jetzt halten mit 2) 100.

auf insgesamt Ich habe eine neue Richtlinie totalOneHundred die aufgerufen erstellt Triggern auf eine Formularänderung, aber ich kann nicht herausfinden, wie auf andere Formularwerte vom link: Rückruf zugegriffen wird.

Ich habe meinen Code unten gepostet. Gibt es etwas, das mir fehlt? Wenn es einen besseren Weg gibt, dies zu erreichen (eine sum() Funktion in der Steuerung und eine ng-show zum Beispiel), rufen Sie mich bitte an.

Danke für Ihre Hilfe.

Die Form:

<!-- input box to be validated --> 
<input type="number" class="form-control" name="lowBound" ng-model="ctrl.lowBound" total-one-hundred required> 

<!-- validation messages --> 
<div ng-messages="form['lowBound'].$error" role="alert"> 
    <div ng-message="required">Cannot be empty</div> 
    <div ng-message="totalOneHundred">Sum of tasks must = 100</div> 
</div> 

<!-- input box to be validated --> 
<input type="number" class="form-control" name="highBound" ng-model="ctrl.highBound" total-one-hundred required> 

<!-- validation messages --> 
<div ng-messages="form['highBound'].$error" role="alert"> 
    <div ng-message="required">Cannot be empty</div> 
    <div ng-message="totalOneHundred">Sum of tasks must = 100</div> 
</div> 

Die Richtlinie:

return { 
    restrict: "A", 

    require: ["^^form", "ngModel"], 

    link: function(scope, element, attributes, controllers) { 

     // At first, form is assigned the actual form controller... 
     const form = controllers[0]; 
     const model = controllers[1]; 

     model.$validators.totalOneHundred = function (modelValue, form, element, scope) { 

      // however, the value of form here is "1". 
      // modelValue is the value of the triggering input, 
      // but how can I access the other form inputs? 
      return true; 

     }; 

    } 
}; 

Antwort

1

Am Anfang nahm ich Ihren Code und umgesetzt this fiddle. Eine sum() Methode des Eltern-Controllers berechnet die Summe (einfach in der Geige, aber da der Eltern-Controller das gesamte, dynamische Modell kennt, ist es auch im realen Fall machbar). Die total-one-hundred nimmt die Summe als Argument, d.h .:

<input type="number" class="form-control" name="lowBound" ng-model="ctrl.lowBound" 
    total-one-hundred="ctrl.sum()" required /> 

Ach, es nicht richtig funktioniert! Problem: Jeder Eingang zeigt den Fehler "Summe der Aufgaben muss 100" an. Wenn Sie ein Feld ändern und die Summe korrekt wird, wird dieses Feld gültig und beendet die Anzeige der Nachricht. Aber die anderen Felder nicht!


EDIT: Nun, es kann Arbeit auch auf diese Weise. Das Geheimnis besteht darin, eine Überwachung der Summe für jede Validierungsanweisung hinzuzufügen und die Validierung für dieses Feld erneut anzuwenden. die neue Link-Funktion:

link: function(scope, element, attributes, controllers) { 
     const model = controllers[0]; 
     var totalEvaluator = $parse(attributes['totalOneHundred']); 

     scope.$watch(totalEvaluator, function(newval, oldval) { 
     if(newval !== oldval) { 
      model.$validate(); 
     } 
     }) 

     model.$validators.totalOneHundred = function (modelValue) { 
     return totalEvaluator(scope) === 100; 
     }; 
    } 

(! beachten, dass dies eine zusätzliche Uhr pro Feld Kosten)

nun jedoch die sum() Funktion (welche möglicherweise teuer sein) oft genannt wird. Die Eingaben dieser Funktion zu beobachten und nur aufzurufen, wenn sie sich ändern, können die Situation verbessern.

Eine aktualisierte Geige: (. Ich ziehe es noch letzte Absatz- -siehe Modellvalidierung aber es ist gut bekannt, alle Alternativen und deren Nebenwirkungen zu sein) https://jsfiddle.net/m8ae0jea/1/


Dies ist ein konzeptionelles Problem mit Feldübergreifende Validierungen. Wo gehört die Validierung? Wenn Sie Ihr Modell so umgestalten können, dass ein gesamtes Objekt validiert wird, können Sie die benutzerdefinierten Steuerelemente von Angular wie in this fiddle verwenden.

Jetzt sieht das Modell wie:

this.model = { 
    lowBound: <a number>, 
    highBound: <a number> 
}; 

Und es ist ein Editor für das gesamte Modell, komplett mit seinen eigenen Nachrichten:

<model-editor name="entireModel" ng-model="ctrl.model" form="form" 
    total-one-hundred="ctrl.sum()"></model-editor> 
<div ng-messages="form['entireModel'].$error" role="alert"> 
    <div ng-message="totalOneHundred">Sum of tasks must = 100</div> 
</div> 

Wie Sie die Gesamtvalidierung des sehen gilt gesamtes Modell.

Das zweite Beispiel funktioniert richtig, wenn Sie mit nur einer einzigen Nachricht für die gesamte "Gesamt" Validierung leben können. Aber ich mag es nicht ...

Angulars Validierung ist (IMHO) eine schnelle und schmutzige Lösung für einfache Dinge geeignet. Angenommen, ein Feld darf nicht leer sein, ein anderes Feld muss einem regulären Ausdruck entsprechen und so weiter. Für komplexe Dinge (wie diesen Fall) finde ich es unangemessen, Geschäftslogik in der Ansicht zu definieren. Ich bevorzuge die Modellvalidierung und verbinde die Validierungsergebnisse mit Angular. Insofern habe ich egkyron geschaffen, was für solche Dinge gut geeignet ist.

+0

Vielen Dank für die ausführliche Antwort. Ich versuche wahrscheinlich, die Winkelvalidierung ein wenig zu weit zu treiben. Ich werde mir die Ressourcen ansehen, die Sie verlinkt haben, und sehen, was für meinen Anwendungsfall am besten passt. Danke noch einmal! – Mac

Verwandte Themen