Angularjs zapobiega przesłaniu formularza, gdy sprawdzanie poprawności danych wejściowych nie powiedzie się


155

Piszę prosty formularz logowania za pomocą angularjs z pewną weryfikacją danych wejściowych po stronie klienta, aby sprawdzić, czy nazwa użytkownika i hasło nie są puste i nie są dłuższe niż trzy znaki. Zobacz poniższy kod:

<form name="loginform" novalidate ng-submit="login.submit()" class="css-form">
    <fieldset>

        <div class="control-group input-prepend">
            <span class="add-on"><i class="icon-user"></i></span>
            <input type="text" ng-model="login.username" name="username" required ng-minlength="3" placeholder="username" />
        </div>

        <div class="control-group input-prepend">
            <span class="add-on"><i class="icon-lock"></i></span>
            <input type="password" ng-model="login.password" name="password" required ng-minlength="3" placeholder="" />
        </div>

        <div class="control-group">
            <input class="btn" type="submit" value="Log in">
        </div>

    </fieldset>
</form>

A kontroler:

var controller = function($scope) {

    $scope.login = {
        submit: function() {

            Console.info($scope.login.username + ' ' + $scope.login.password);
        }
    }

};

Problem polega na tym, że login.submitfunkcja zostanie wywołana, nawet jeśli dane wejściowe będą nieprawidłowe. Czy można temu zapobiec?

Na marginesie mogę wspomnieć, że używam również bootstrap i requirejs.



czy możemy go użyć bez tagu formularza i nadal form.valid będzie działać na ng-click!
Rizwan Patel

Odpowiedzi:


329

Możesz to zrobić:

<form name="loginform" novalidate ng-submit="loginform.$valid && login.submit()">

Nie ma potrzeby sprawdzania kontrolera.


8
To powinna być akceptowana odpowiedź. Nie trzeba niczego sprawdzać w kontrolerze
Howie,

10
Nie zgadzam się z „brakiem potrzeby kontroli kontrolerów”. Co się stanie, jeśli w funkcji przesyłania wystąpią dodatkowe sprawdzenia poprawności.
SlaterCodes

6
Przeprowadź dodatkową walidację w dyrektywie. Zaktualizuj walidację za pomocą $ setValidity.
TMB

@ b1tsh1ft Byłoby lepiej, aby bieżący stan walidacji był zawsze znany, a nie obliczany podczas przesyłania. W pewnym sensie chodzi o walidację Angulara. Nie możesz mieć żadnego wizualnego wskazania nieprawidłowego stanu, gdy zakres nie wie o tym.
Kevin Beal

1
Wypróbowałem to podejście, ale wygląda na to, że ocenia oba (tzn. Nie powoduje zwarcia wartości logicznej po tym, &&jak próbowałem przekazać wartość w ramach przesyłania i potwierdziłem, że sama wartość jest „fałszywa”
Archimedes Trajano

67

Zmień przycisk przesyłania na:

<button type="submit" ng-disabled="loginform.$invalid">Login</button>

1
Świetna odpowiedź. Rządzisz!
Harsha.Vaswani

24
Nadal możesz przesłać formularz, naciskając klawisz Enter, gdy pole wprowadzania jest aktywne!
fabsenet

2
@Red: patrz komentarz powyżej.
Andrei Rînea

Chociaż wyłączenie przycisku jest zwykle najlepszym sposobem rozwiązania tego problemu, nie o to prosił OP.
dołu

1
Połączenie tej techniki w celu zapewnienia wizualnej informacji zwrotnej użytkownikowi wraz z odpowiedzią @Yashua, aby zapobiec przesłaniu formularza, jest idealne. Dzięki!
tkarls

43

Więc sugerowana odpowiedź z TheHippo nie zadziałała dla mnie, zamiast tego wysłałem formularz jako parametr do funkcji takiej jak:

<form name="loginform" novalidate ng-submit="login.submit(loginForm)" class="css-form">

Dzięki temu formularz jest dostępny w metodzie kontrolera:

$scope.login = {
    submit : function(form) {
        if(form.$valid)....
    }

Miałem ten sam problem. Jednak użycie twojej metody zadziałało.
Panda4Man

Jest to nieco lepsze niż zaakceptowana odpowiedź, ponieważ sprawdzanie poprawności formularza. $ Jest wykonywane w JS, a nie w HTML.
cellepo

Jednak nie sądzę, abyś musiał przekazać loginForm, aby przesłać funkcję: myślę, że $ scope.loginform powinien być dostępny w JS (przynajmniej był dla mnie), więc możesz zastąpić formularz. $ Valid na $ scope.loginform . $ ważne.
cellepo

13

Twoje formularze są automatycznie umieszczane w $ scope jako obiekt. Dostęp do niego można uzyskać za pośrednictwem$scope[formName]

Poniżej znajduje się przykład, który będzie działał z oryginalną konfiguracją i bez konieczności przekazywania samego formularza jako parametru w ng-submit.

var controller = function($scope) {

    $scope.login = {
        submit: function() {
            if($scope.loginform.$invalid) return false;

        }
    }

};

Przykład roboczy: http://plnkr.co/edit/BEWnrP?p=preview


4
W jaki sposób uzyskasz dostęp do formularza, jeśli użyjesz notacji „As Controller” zamiast $ scope?
masimplo

@masimakopoulos: Zamiast tego możesz po prostu użyć if(this.loginform.$invalid).., ale wtedy w kodzie HTML musisz nadać formularzowi nazwę <form name="ctrl.loginform" ... I to przy założeniu, że używasz <div ng-controller="controller as ctrl"..w składni kontrolera jako. Dzięki @JoshCaroll
Bart

13

HTML:

<div class="control-group">
    <input class="btn" type="submit" value="Log in" ng-click="login.onSubmit($event)">
</div>

W kontrolerze:

$scope.login = {
    onSubmit: function(event) {
        if (dataIsntValid) {
            displayErrors();
            event.preventDefault();
        }
        else {
            submitData();
        }
    }
}

czy naprawdę konieczne jest sprawdzenie metody onsubmit? Oznacza to, że musisz sprawdzić, czy dane wejściowe spełniają wszystkie kryteria zarówno w znaczniku (przez kąt), jak iw kodzie js. Moim zdaniem angular nie powinien wywoływać onsubmit, gdy dane wejściowe są nieprawidłowe. zobacz benlesh.com/2012/11/angular-js-form-validation.html z informacją „ng-submit nie można wywołać, dopóki cały formularz nie będzie prawidłowy”
Runar Halse

Możesz również wyłączyć przycisk, aby nie zezwalać na przesyłanie, jeśli formularz jest ważny. Możesz również skorzystać z formularza ng-submit. Jeśli angular nie obsługuje walidacji formularza event.preventDefault(), najlepszym rozwiązaniem jest zatrzymanie przesyłania formularzy.
TheHippo

@RunarHalse Naprawdę konieczne jest sprawdzenie. Zgadzam się z Tobą, że nie powinno tak być. Przyczyną, dla której metoda onsubmit nie jest wywoływana w połączonym przykładzie, jest to, że ten przykład nie ma ustawionego novalidate. Przeglądarka uniemożliwia wywołanie zdarzeń, a nie Angular. Oto jego przykład z nobalidate na: plnkr.co/edit/R0C8XA?p=preview . Zwróć uwagę na przesłanie formularza.
davidmdem

idealne właśnie to, czego szukałem, sposób na zablokowanie przesyłania formularzy za pomocą
angular

3

Chociaż nie jest to bezpośrednie rozwiązanie dla pytania PO, jeśli twój formularz jest w ng-appkontekście, ale chcesz, aby Angular całkowicie go zignorował, możesz to zrobić bezpośrednio za pomocą ngNonBindabledyrektywy:

<form ng-non-bindable>
  ...
</form>

2

Aby dodać do powyższych odpowiedzi,

Miałem 2 zwykłe przyciski, jak pokazano poniżej. (Nigdzie nie ma typu = „wyślij”)

<button ng-click="clearAll();" class="btn btn-default">Clear Form</button>
<button ng-disabled="form.$invalid" ng-click="submit();"class="btn btn-primary pull-right">Submit</button>

Bez względu na to, jak bardzo się starałem, naciskając klawisz Enter, gdy formularz był już ważny , został wywołany przycisk „Wyczyść formularz”, który wyczyścił cały formularz.

Aby obejść ten problem,

Musiałem dodać fałszywy przycisk przesyłania, który był wyłączony i ukryty. A ten fałszywy przycisk musiał znajdować się nad wszystkimi innymi przyciskami, jak pokazano poniżej .

<button type="submit" ng-hide="true" ng-disabled="true">Dummy</button>

<button ng-click="clearAll();" class="btn btn-default">Clear Form</button>

<button ng-disabled="form.$invalid" ng-click="submit();"class="btn btn-primary pull-right">Submit</button>

Cóż, moim zamiarem było nigdy nie poddawać się na Enter, więc powyższy hack działa dobrze.


możesz również zatrzymać przesyłanie po naciśnięciu klawisza Enter, usuwając atrybut on ng-submit z formularza
Kieran

1

Wiem, że to stary wątek, ale pomyślałem, że też będę miał swój wkład. Moje rozwiązanie jest podobne do posta już oznaczonego jako odpowiedź. Niektóre wbudowane testy JavaScript załatwiają sprawę.

ng-click="form.$invalid ? alert('Please correct the form') : saveTask(task)"

1
Nadal możesz przesłać formularz, naciskając klawisz Enter, gdy pole wprowadzania jest aktywne!
Yevgeniy Afanasjew

0

Wiem, że jest późno i otrzymałem odpowiedź, ale chciałbym podzielić się zgrabnymi rzeczami, które zrobiłem. Stworzyłem dyrektywę ng-validate, która przechwytuje przy przesłaniu formularza, a następnie wysyła metodę Prevention-default, jeśli $ eval jest fałszywe:

app.directive('ngValidate', function() {
  return function(scope, element, attrs) {
    if (!element.is('form'))
        throw new Error("ng-validate must be set on a form elment!");

    element.bind("submit", function(event) {
        if (!scope.$eval(attrs.ngValidate, {'$event': event}))
            event.preventDefault();
        if (!scope.$$phase)
            scope.$digest();            
    });
  };
});

W Twoim html:

<form name="offering" method="post" action="offer" ng-validate="<boolean expression">
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.