Trigger-Validierung aller Felder in Angular Form Submit

81

Ich verwende diese Methode: http://plnkr.co/edit/A6gvyoXbBd2kfToPmiiA?p=preview, um nur Felder bei Unschärfe zu überprüfen. Dies funktioniert einwandfrei, aber ich möchte sie auch validieren (und daher die Fehler für diese Felder anzeigen, falls vorhanden), wenn der Benutzer auf die Schaltfläche "Senden" klickt (kein echtes Senden, sondern ein Daten-Klick-Aufruf einer Funktion).

Gibt es eine Möglichkeit, die Validierung aller Felder erneut auszulösen, wenn Sie auf diese Schaltfläche klicken?

Maarten
quelle
Wo ist der Knopf im Plunkr?
Callmekatootie
Entschuldigung, auf dem Plunker habe ich meinen Code aufgebaut. Ich habe eine Gabelung gemacht, um meiner Situation näher zu kommen: plnkr.co/edit/VfvCSmjlzpIgUH4go2Jn?p=preview
Maarten

Antworten:

44

Was für mich $setSubmittedfunktioniert hat, war die Verwendung der Funktion, die zuerst in den eckigen Dokumenten in Version 1.3.20 angezeigt wird.

In dem Klickereignis, in dem ich die Validierung auslösen wollte, habe ich Folgendes ausgeführt:

vm.triggerSubmit = function() {
    vm.homeForm.$setSubmitted();
    ...
}

Das war alles was ich brauchte. Laut den Dokumenten "Setzt das Formular auf den übermittelten Zustand." Es wird hier erwähnt .

Entwicklung
quelle
4
Dies funktioniert nicht, wenn Sie verwenden ng-messagesund sie nur anzeigen, wenn $ error && $ schmutzig ist .
JobaDiniz
@JobaDiniz Haben Sie die $ setDirty-Funktion ausprobiert? Es wird auch in dem Link aus meiner Antwort erwähnt: code.angularjs.org/1.3.20/docs/api/ng/type/form.FormController Hoffe, das hilft!
Entwicklung
2
es funktioniert nicht für form... Ich musste alle Eingänge durchlaufen und sie aufrufen $setDirty().
JobaDiniz
43

Ich weiß, es ist ein bisschen zu spät, um zu antworten, aber alles, was Sie tun müssen, ist, alle Formen schmutzig zu machen. Schauen Sie sich den folgenden Ausschnitt an:

angular.forEach($scope.myForm.$error.required, function(field) {
    field.$setDirty();
});

und dann können Sie überprüfen, ob Ihr Formular gültig ist, indem Sie:

if($scope.myForm.$valid) {
    //Do something
}   

und schließlich, denke ich, möchten Sie Ihre Route ändern, wenn alles gut aussieht:

$location.path('/somePath');

Bearbeiten : Das Formular registriert sich erst dann im Bereich, wenn das Senden-Ereignis ausgelöst wird. Verwenden Sie einfach die Anweisung ng-submit, um eine Funktion aufzurufen, und wickeln Sie das Obige in diese Funktion ein, und es sollte funktionieren.

Thilak Rao
quelle
1
Können Sie ein Beispiel für die programmgesteuerte Auslösung einer ng-submitDirektive angeben ?
Chovy
@chovy ng-submitbindet einfach eine Funktion an das Submit- Ereignis. Warum nicht einfach diese Funktion aufrufen?
Thilak Rao
Ich habe eine Direktive in das Formular eingebettet, die ein Formularfeld außerhalb der Direktive aktualisiert. Der Validator wird nur angewendet, wenn ich auf das zu validierende Formularfeld klicke und es verwische.
Chovy
Ich werde nicht das Formularobjekt haben, das an es übergeben wird
chovy
@chovy Ich verstehe dich nicht richtig. Aber lassen Sie mich versuchen, Ihnen zu helfen. Haben Sie versucht, beim Entprellen zu validieren?
Thilak Rao
17

Für den Fall, dass jemand später darauf zurückkommt ... Keiner der oben genannten Punkte hat für mich funktioniert. Also habe ich mich in die Eingeweide der Winkelformvalidierung vertieft und die Funktion gefunden, die sie aufrufen, um Validatoren für ein bestimmtes Feld auszuführen. Diese Eigenschaft wird bequem genannt $validate.

Wenn Sie ein benanntes Formular haben myForm, können Sie programmgesteuert aufrufen myForm.my_field.$validate(), um die Feldüberprüfung auszuführen. Zum Beispiel:

<div ng-form name="myForm">
    <input required name="my_field" type="text" ng-blur="myForm.my_field.$validate()">
</div>

Beachten Sie, dass das Aufrufen $validateAuswirkungen auf Ihr Modell hat. Aus den eckigen Dokumenten für ngModelCtrl. $ Validieren:

Führt jeden der registrierten Validatoren aus (zuerst synchrone Validatoren und dann asynchrone Validatoren). Wenn sich die Gültigkeit in ungültig ändert, wird das Modell auf undefiniert gesetzt, es sei denn, ngModelOptions.allowInvalid ist true. Wenn sich die Gültigkeit in gültig ändert, wird das Modell auf den letzten verfügbaren gültigen $ modelValue gesetzt, dh entweder auf den zuletzt analysierten Wert oder auf den zuletzt aus dem Bereich festgelegten Wert.

Wenn Sie also vorhaben, etwas mit dem ungültigen Modellwert zu tun (z. B. eine Nachricht zu veröffentlichen, die dies mitteilt), müssen Sie sicherstellen allowInvalid, dass truefür Ihr Modell die Option "eingestellt" ist .

Chukkwagon
quelle
Weitere Diskussionen über das sehr überraschende Ergebnis "Modell wird undefiniert" in Abwesenheit von allowInvalidkönnen hier gelesen werden: github.com/angular/angular.js/issues/10035
pestophagous
12

Mit Angular-Validator können Sie tun, was Sie wollen. Es ist einfach dumm zu bedienen.

Es wird:

  • Überprüfen Sie nur die Felder ein $dirtyoder aussubmit
  • Verhindern Sie, dass das Formular gesendet wird, wenn es ungültig ist
  • Benutzerdefinierte Fehlermeldung anzeigen, nachdem das Feld $dirtyoder das Formular gesendet wurde

Siehe die Demo

Beispiel

<form angular-validator 
       angular-validator-submit="myFunction(myBeautifulForm)"
       name="myBeautifulForm">
       <!-- form fields here -->
    <button type="submit">Submit</button>
</form>

Wenn das Feld das nicht besteht, kann der validatorBenutzer das Formular nicht senden.

Check out Winkel Validator Anwendungsfälle und Beispiele für weitere Informationen.

Haftungsausschluss: Ich bin der Autor von Angular-Validator

user3920706
quelle
11

Nun, der eckige Weg wäre, es die Validierung durchführen zu lassen - da dies bei jedem Modellwechsel der Fall ist - und das Ergebnis dem Benutzer nur dann anzuzeigen, wenn Sie dies wünschen.

In diesem Fall entscheiden Sie, wann die Fehler angezeigt werden sollen. Sie müssen lediglich ein Flag setzen: http://plnkr.co/edit/0NNCpQKhbLTYMZaxMQ9l?p=preview

Soweit ich weiß, wurde ein Problem bei Angular eingereicht, um eine erweiterte Formularsteuerung zu ermöglichen. Da es nicht gelöst ist, würde ich dies verwenden, anstatt alle vorhandenen Validierungsmethoden neu zu erfinden.

Bearbeiten: Aber wenn Sie auf Ihrem Weg bestehen, ist hier Ihre modifizierte Geige mit Validierung vor dem Absenden. http://plnkr.co/edit/Xfr7X6JXPhY9lFL3hnOw?p=preview Der Controller sendet ein Ereignis, wenn auf die Schaltfläche geklickt wird, und die Direktive führt die Validierungsmagie aus.

Oliver
quelle
Dies funktioniert in diesem Beispiel, aber was ist, wenn ich, wie ich es in meinem Fall getan habe (aber nicht in diesem plunkr..sorry!), Mehr als eine Direktive wie diese per E-Mail. Müsste ich die Validierung irgendwie aus den Direktiven in eine separate Validierungsklasse verschieben und dann alle Validierungsmethoden dieses Formulars aufrufen, oder könnte ich die Validierung für alle Direktiven auf andere Weise auslösen? Da die Validierung durch Unschärfe ausgelöst wird, können möglicherweise sogar Unschärfen aus dem Code ausgelöst werden, aber das scheint schrecklich.
Maarten
Oh und ich weiß über das Problem Bescheid. Leider ist es noch nicht in der Beta und der Workflow, über den ich spreche, ist für dieses Unternehmen erforderlich
Maarten
Das gesendete Ereignis löst in jeder Direktive den $ on-Rückruf aus, da alle im Bereich des Controllers liegen.
Oliver
ahh ... habe diesen Teil nicht wirklich verstanden. Vielen Dank!
Maarten
1
Wenn Sie das Ereignis senden, können Sie Parameter übergeben. $ scope. $ Broadcast ('startValidations', param1, param2); Das Listen bleibt unverändert: scope. $ On ('startValidations', validateMe); Und im Rückruf fn: function validateMe (event, param1, param2) {} Siehe Dokumentation: docs.angularjs.org/api/ng.$rootScope.Scope#$broadcast
Oliver
9

Ein Ansatz besteht darin, zu erzwingen, dass alle Attribute verschmutzt sind. Sie können das in jedem Controller tun, aber es wird sehr chaotisch. Es wäre besser, eine allgemeine Lösung zu haben.

Der einfachste Weg, den ich mir vorstellen konnte, war die Verwendung einer Richtlinie

  • Es wird das Formular-Submit-Attribut verarbeiten
  • Es durchläuft alle Formularfelder und markiert makellose Felder als verschmutzt
  • Es prüft, ob das Formular gültig ist, bevor die Übermittlungsfunktion aufgerufen wird

Hier ist die Richtlinie

myModule.directive('submit', function() {
  return {
    restrict: 'A',
    link: function(scope, formElement, attrs) {
      var form;
      form = scope[attrs.name];
      return formElement.bind('submit', function() {
        angular.forEach(form, function(field, name) {
          if (typeof name === 'string' && !name.match('^[\$]')) {
            if (field.$pristine) {
              return field.$setViewValue(field.$value);
            }
          }
        });
        if (form.$valid) {
          return scope.$apply(attrs.submit);
        }
      });
    }
  };
});

Und aktualisieren Sie Ihr Formular-HTML, zum Beispiel:

 <form ng-submit='justDoIt()'>

wird:

 <form name='myForm' novalidate submit='justDoIt()'>

Ein vollständiges Beispiel finden Sie hier: http://plunker.co/edit/QVbisEK2WEbORTAWL7Gu?p=preview

joshnuss
quelle
4

Hier ist meine globale Funktion zum Anzeigen der Formularfehlermeldungen.

 function show_validation_erros(form_error_object) {
        angular.forEach(form_error_object, function (objArrayFields, errorName) {
            angular.forEach(objArrayFields, function (objArrayField, key) {
                objArrayField.$setDirty();
            });
        });
    };

Und in meinen Controllern,

if ($scope.form_add_sale.$invalid) { 
    $scope.global.show_validation_erros($scope.form_add_sale.$error);
}
Namal
quelle
1
Dies beantwortet die Frage nicht.
Rafael Herscovici
Ich habe meine Antwort geändert. Bitte überprüfen Sie es jetzt
Namal
2

Basierend auf Thilaks Antwort konnte ich diese Lösung finden ...

Da in meinen Formularfeldern nur Validierungsnachrichten angezeigt werden, wenn ein Feld ungültig ist und vom Benutzer berührt wurde, konnte ich diesen durch eine Schaltfläche ausgelösten Code verwenden, um meine ungültigen Felder anzuzeigen:

// Show/trigger any validation errors for this step
angular.forEach(vm.rfiForm.stepTwo.$error, function(error) {
  angular.forEach(error, function(field) {
    field.$setTouched();
  });
});
// Prevent user from going to next step if current step is invalid
if (!vm.rfiForm.stepTwo.$valid) {
  isValid = false;
}
<!-- form field -->
<div class="form-group" ng-class="{ 'has-error': rfi.rfiForm.stepTwo.Parent_Suffix__c.$touched && rfi.rfiForm.stepTwo.Parent_Suffix__c.$invalid }">

  <!-- field label -->
  <label class="control-label">Suffix</label>
  <!-- end field label -->
  <!-- field input -->
  <select name="Parent_Suffix__c" class="form-control"
          ng-options="item.value as item.label for item in rfi.contact.Parent_Suffixes"
          ng-model="rfi.contact.Parent_Suffix__c" />
  <!-- end field input -->
  <!-- field help -->
  <span class="help-block" ng-messages="rfi.rfiForm.stepTwo.Parent_Suffix__c.$error" ng-show="rfi.rfiForm.stepTwo.Parent_Suffix__c.$touched">
    <span ng-message="required">this field is required</span>
  </span>  
  <!-- end field help -->
</div>
<!-- end form field -->

Charles Naccio
quelle
2

Hinweis: Ich weiß, dass dies ein Hack ist, aber es war nützlich für Angular 1.2 und früher, das keinen einfachen Mechanismus bot.

Die Validierung startet das Änderungsereignis , sodass einige Dinge wie das programmgesteuerte Ändern der Werte es nicht auslösen. Das Auslösen des Änderungsereignisses löst jedoch die Validierung aus. Zum Beispiel mit jQuery:

$('#formField1, #formField2').trigger('change');
Jacob Mouka
quelle
Dieser Ansatz ist einfach. Außerdem hat es den Vorteil, dass es auf älteren (allen) Versionen von Angular funktioniert.
Paul LeBeau
3
Nicht das angular way.
Rafael Herscovici
1

Um alle Felder meines Formulars zu validieren, wenn ich möchte, führe ich eine Validierung für jedes Feld von $$ -Steuerelementen wie folgt durch:

angular.forEach($scope.myform.$$controls, function (field) {
    field.$validate();
});
stephaneb
quelle
0

Ich mag diesen Ansatz bei der Handhabung der Validierung beim Klicken auf eine Schaltfläche.

  1. Es ist nicht erforderlich, etwas vom Controller aufzurufen.

  2. Es wird alles mit einer Richtlinie behandelt.

auf Github

Sathish Naga
quelle
0

Sie können dies versuchen:

// The controller

$scope.submitForm = function(form){
   		//Force the field validation
   		angular.forEach(form, function(obj){
   			if(angular.isObject(obj) && angular.isDefined(obj.$setDirty))
   			{ 
   				obj.$setDirty();
   			}
   		})
        
        if (form.$valid){
		
			$scope.myResource.$save(function(data){
		     	//....
			});
		}
}
<!-- FORM -->

  <form name="myForm"  role="form" novalidate="novalidate">
<!-- FORM GROUP to field 1 -->
  <div class="form-group" ng-class="{ 'has-error' : myForm.field1.$invalid && myForm.field1.$dirty }">
      <label for="field1">My field 1</label>
        <span class="nullable"> 
        <select name="field1" ng-model="myresource.field1" ng-options="list.id as list.name for list in listofall"
          class="form-control input-sm" required>
            <option value="">Select One</option>
        </select>
        </span>
        <div ng-if="myForm.field1.$dirty" ng-messages="myForm.field1.$error" ng-messages-include="mymessages"></div>
  </div>
    
<!-- FORM GROUP to field 2 -->
  <div class="form-group" ng-class="{ 'has-error' : myForm.field2.$invalid && myForm.field2.$dirty }">
    <label class="control-label labelsmall" for="field2">field2</label> 
      <input name="field2" min="1" placeholder="" ng-model="myresource.field2" type="number" 
      class="form-control input-sm" required>
    <div ng-if="myForm.field2.$dirty" ng-messages="myForm.field2.$error" ng-messages-include="mymessages"></div>
  </div>

  </form>

<!-- ... -->
<button type="submit" ng-click="submitForm(myForm)">Send</button>

Vinicius Trindade
quelle
0

Ich habe etwas getan, damit es funktioniert.

<form name="form" name="plantRegistrationForm">
  <div ng-class="{ 'has-error': (form.$submitted || form.headerName.$touched) && form.headerName.$invalid }">
    <div class="col-md-3">
      <div class="label-color">HEADER NAME 
        <span class="red"><strong>*</strong></span></div>
    </div>
    <div class="col-md-9">
      <input type="text" name="headerName" id="headerName" 
             ng-model="header.headerName" 
             maxlength="100" 
             class="form-control" required>
      <div ng-show="form.$submitted || form.headerName.$touched">
        <span ng-show="form.headerName.$invalid" 
              class="label-color validation-message">Header Name is required</span>
      </div>
    </div>
  </div>

  <button ng-click="addHeader(form, header)" 
          type="button" 
          class="btn btn-default pull-right">Add Header
  </button>

</form>

In Ihrem Controller können Sie tun;

addHeader(form, header){
        let self = this;
        form.$submitted = true;
        ... 
    }

Sie brauchen auch etwas CSS;

.label-color {
            color: $gray-color;
        }
.has-error {
       .label-color {
            color: rgb(221, 25, 29);
        }
        .select2-choice.ui-select-match.select2-default {
            border-color: #e84e40;
        }
    }
.validation-message {
       font-size: 0.875em;
    }
    .max-width {
        width: 100%;
        min-width: 100%;
    }
Mahib
quelle