Wyzwalanie weryfikacji wszystkich pól w przesyłaniu formularza kątowego

81

Używam tej metody: http://plnkr.co/edit/A6gvyoXbBd2kfToPmiiA?p=preview, aby sprawdzać tylko pola przy rozmyciu. Działa to dobrze, ale chciałbym również je zweryfikować (a tym samym pokazać błędy tych pól, jeśli występują), gdy użytkownik kliknie przycisk `` prześlij '' (nie jest to prawdziwe przesłanie, ale wywołanie funkcji data-ng-click)

Czy istnieje sposób, aby ponownie uruchomić walidację wszystkich pól po kliknięciu tego przycisku?

Maarten
źródło
Gdzie jest przycisk w plunkrze?
callmekatootie
przepraszam, plunker jest tym, na czym oparłem swój kod. Zrobiłem widelec, aby bardziej przypominał moją sytuację: plnkr.co/edit/VfvCSmjlzpIgUH4go2Jn?p=preview
Maarten

Odpowiedzi:

44

U mnie zadziałało użycie $setSubmittedfunkcji, która po raz pierwszy pojawia się w dokumentach kątowych w wersji 1.3.20.

W przypadku kliknięcia, w którym chciałem uruchomić walidację, wykonałem następujące czynności:

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

To było wszystko, czego potrzebowałem. Zgodnie z dokumentacją „Ustawia formularz na stan przedłożony”. Jest to tutaj wymienione .

rozwój
źródło
4
to nie działa, gdy używasz ng-messagesi wyświetlasz je tylko wtedy, gdy $ error && $ dirty .
JobaDiniz
@JobaDiniz Czy wypróbowałeś funkcję $ setDirty? Wspomina o tym także link z mojej odpowiedzi: code.angularjs.org/1.3.20/docs/api/ng/type/form.FormController Mam nadzieję, że to pomoże!
rozwijanie
2
to nie działa dla form... Musiałem przelecieć przez wszystkie wejścia i wywołać $setDirty()je.
JobaDiniz
43

Wiem, że na odpowiedź jest trochę za późno, ale wszystko, co musisz zrobić, to zabrudzić wszystkie formularze. Spójrz na następujący fragment:

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

a następnie możesz sprawdzić, czy Twój formularz jest ważny za pomocą:

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

i na koniec myślę, że chciałbyś zmienić trasę, jeśli wszystko wygląda dobrze:

$location.path('/somePath');

Edycja : formularz nie zarejestruje się w zakresie, dopóki nie zostanie wyzwolone zdarzenie przesyłania. Po prostu użyj dyrektywy ng-submit, aby wywołać funkcję i zawinąć powyższe funkcje w tę funkcję, a powinno działać.

Thilak Rao
źródło
1
czy możesz podać przykład ng-submitdyrektywy wyzwalającej programowo ?
chovy
@chovy ng-submitpo prostu wiąże funkcję ze zdarzeniem przesyłania, dlaczego nie wywołać tej funkcji?
Thilak Rao
Mam dyrektywę osadzoną w formularzu, która aktualizuje pole formularza poza dyrektywą… walidator nie jest stosowany, chyba że kliknę i zamazam pole formularza, które chcę zweryfikować.
chovy
nie będę mieć obiektu formularza, który zostanie do niego przekazany
chovy
@chovy Nie rozumiem cię poprawnie. Ale spróbuję ci pomóc. Czy próbowałeś sprawdzać poprawność przy odbiciu?
Thilak Rao
17

Na wypadek, gdyby ktoś wrócił do tego później ... Żadne z powyższych nie zadziałało dla mnie. Więc zagłębiłem się w wnętrzności walidacji formy kątowej i znalazłem funkcję, którą wywołują, aby wykonać walidatory na danym polu. Ta właściwość jest dogodnie nazywana $validate.

Jeśli masz nazwany formularz myForm, możesz programowo wywołać w myForm.my_field.$validate()celu wykonania walidacji pola. Na przykład:

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

Pamiętaj, że wywołanie $validatema wpływ na Twój model. Z dokumentacji kątowej dla ngModelCtrl. $ Validate:

Uruchamia każdy z zarejestrowanych walidatorów (najpierw walidatory synchroniczne, a następnie walidatory asynchroniczne). Jeśli ważność zmieni się na nieprawidłową, model zostanie ustawiony na niezdefiniowany, chyba że wartość ngModelOptions.allowInvalid jest true. Jeśli ważność zmieni się na prawidłową, ustawi model na ostatnią dostępną prawidłową wartość $ modelValue, tj. Albo ostatnią przeanalizowaną wartość, albo ostatnią wartość ustawioną z zakresu.

Więc jeśli planujesz zrobić coś z nieprawidłową wartością modelu (np. Wyświetlenie komunikatu informującego o tym), musisz się upewnić allowInvalid jest ustawiony na truedla twojego modelu.

chukkwagon
źródło
więcej dyskusji na temat bardzo zaskakującego wyniku "model staje się niezdefiniowany" w przypadku braku allowInvalidmożna przeczytać tutaj: github.com/angular/angular.js/issues/10035
pestophagous
12

Możesz użyć Angular-Validator, aby robić, co chcesz. To głupie, proste w użyciu.

To będzie:

  • Sprawdzaj tylko pola włączone $dirtylub włączonesubmit
  • Zapobiegaj przesyłaniu formularza, jeśli jest nieprawidłowy
  • Pokaż niestandardowy komunikat o błędzie po przesłaniu pola $dirtylub formularza

Zobacz demo

Przykład

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

Jeśli pole nie spełnia validatorwarunków, użytkownik nie będzie mógł wysłać formularza.

Aby uzyskać więcej informacji, zobacz przykłady użycia i przykłady użycia walidatorów kątowych .

Zastrzeżenie: jestem autorem Angular-Validator

user3920706
źródło
11

Cóż, kątowym sposobem byłoby pozwolić mu zająć się walidacją - ponieważ robi to przy każdej zmianie modelu - i pokazać wynik użytkownikowi tylko wtedy, gdy chcesz.

W tym przypadku decydujesz, kiedy pokazać błędy, wystarczy ustawić flagę: http://plnkr.co/edit/0NNCpQKhbLTYMZaxMQ9l?p=preview

O ile wiem, zgłoszony został problem do kątowego, aby umożliwić nam bardziej zaawansowaną kontrolę nad formularzami. Ponieważ nie został rozwiązany, użyłbym tego zamiast wymyślać na nowo wszystkie istniejące metody walidacji.

edycja: Ale jeśli nalegasz na swoją drogę, oto twoje zmodyfikowane skrzypce z walidacją przed przesłaniem. http://plnkr.co/edit/Xfr7X6JXPhY9lFL3hnOw?p=preview Kontroler emituje zdarzenie po kliknięciu przycisku, a dyrektywa wykonuje magię walidacji.

Oliver
źródło
To działa w tym przykładzie, ale co jeśli ja, tak jak w moim przypadku (ale nie w tym plunkr..przepraszam!), Więcej niż jedną dyrektywę, taką jak ta e-mailowa. Czy musiałbym w jakiś sposób przenieść walidację z dyrektyw do oddzielnej klasy walidacji, a następnie wywołać wszystkie metody walidacji tego formularza, czy może w jakiś sposób wyzwolić walidację w inny sposób dla wszystkich dyrektyw. Ponieważ walidacja jest wyzwalana przez rozmycie, może nawet wywołać rozmycie z kodu, ale wydaje się to okropne.
Maarten
Aha i wiem o problemie. Niestety nie jest jeszcze w wersji beta, a przepływ pracy, o którym mówię, jest wymagany dla tej firmy
Maarten
Rozgłaszane zdarzenie wyzwoli $ on callback w każdej dyrektywie, ponieważ wszystkie z nich są objęte zakresem kontrolera.
Oliver
ahh ... tak naprawdę nie rozumiałem tej części. Dzięki!
Maarten
1
Podczas transmisji wydarzenia możesz przekazywać parametry. $ scope. $ broadcast ('startValidations', param1, param2); Odsłuch pozostaje niezmieniony: scope. $ On ('startValidations', validateMe); A w wywołaniu zwrotnym fn: function validateMe (event, param1, param2) {} Zobacz dokumentację: docs.angularjs.org/api/ng.$rootScope.Scope#$broadcast
Oliver
9

Jednym ze sposobów jest wymuszenie zabrudzenia wszystkich atrybutów. Możesz to zrobić w każdym kontrolerze, ale robi się bardzo bałagan. Lepiej byłoby mieć ogólne rozwiązanie.

Najłatwiejszym sposobem, o jakim przyszło mi do głowy, było użycie dyrektywy

  • obsłuży atrybut przesyłania formularza
  • iteruje przez wszystkie pola formularza i zaznacza nieskazitelne pola jako brudne
  • sprawdza, czy formularz jest ważny przed wywołaniem funkcji przesyłania

Oto dyrektywa

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

I zaktualizuj swój formularz html, na przykład:

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

staje się:

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

Zobacz pełny przykład tutaj: http://plunker.co/edit/QVbisEK2WEbORTAWL7Gu?p=preview

joshnuss
źródło
4

Oto moja globalna funkcja do wyświetlania komunikatów o błędach formularza.

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

A w moich kontrolerach

if ($scope.form_add_sale.$invalid) { 
    $scope.global.show_validation_erros($scope.form_add_sale.$error);
}
Namal
źródło
1
To nie odpowiada na pytanie.
Rafael Herscovici
Zmieniłem odpowiedź. Sprawdź to teraz
Namal
2

Na podstawie odpowiedzi Thilaka udało mi się wymyślić takie rozwiązanie ...

Ponieważ moje pola formularza pokazują komunikaty walidacji tylko wtedy, gdy pole jest nieprawidłowe i zostało dotknięte przez użytkownika, mogłem użyć tego kodu uruchamianego przez przycisk, aby wyświetlić moje nieprawidłowe pola:

// 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
źródło
2

Uwaga: wiem, że to hack, ale był przydatny w Angular 1.2 i wcześniejszych, które nie zapewniały prostego mechanizmu.

Walidacja rozpoczyna się w zdarzeniu zmiany , więc niektóre rzeczy, takie jak programowa zmiana wartości, nie wyzwoli go. Ale wyzwolenie zdarzenia zmiany wyzwoli walidację. Na przykład z jQuery:

$('#formField1, #formField2').trigger('change');
Jacob Mouka
źródło
To podejście jest proste. Dodatkowo ma tę zaletę, że działa na starszych (wszystkich) wersjach Angulara.
Paul LeBeau,
3
Nie angular way.
Rafael Herscovici
0

Podoba mi się to podejście do obsługi walidacji po kliknięciu przycisku.

  1. Nie ma potrzeby wywoływania czegokolwiek z kontrolera,

  2. wszystko jest obsługiwane za pomocą dyrektywy.

na github

Sathish Naga
źródło
0

Możesz spróbować tego:

// 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
źródło
0

Zrobiłem coś później, aby to zadziałało.

<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>

W swoim kontrolerze możesz to zrobić;

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

Potrzebujesz też 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
źródło
0

Aby zweryfikować wszystkie pola mojego formularza, kiedy chcę, przeprowadzam walidację każdego pola kontrolek $$ w następujący sposób:

angular.forEach($scope.myform.$$controls, function (field) {
    field.$validate();
});
stephaneb
źródło