Angularjs impedisce l'invio del modulo quando la convalida dell'input non riesce


155

Sto scrivendo un semplice modulo di accesso utilizzando angularjs con alcune convalide dell'input lato client per verificare che il nome utente e la password non siano vuoti e più lunghi di tre caratteri. Vedi il codice seguente:

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

E il controller:

var controller = function($scope) {

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

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

};

Il problema è che la login.submitfunzione verrà chiamata anche se l'ingresso non è valido. È possibile prevenire questo comportamento?

Come nota a margine, posso menzionare che uso anche bootstrap e requisjs.



possiamo usarlo senza tag form e ancora form.valid funzionerebbe su ng-click!
Rizwan Patel,

Risposte:


329

Tu puoi fare:

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

Non sono necessari controlli del controller.


8
Questa dovrebbe essere la risposta accettata. Non è necessario controllare nulla nel controller
Howie,

10
Non sono d'accordo con "nessuna necessità di controlli del controller". Che cosa succede se si verificano ulteriori controlli di convalida nella funzione di invio.
SlaterCodes

6
Eseguire la convalida aggiuntiva nella direttiva. Aggiorna la convalida con $ setValidity.
TMB,

@ b1tsh1ft Sarebbe preferibile che lo stato corrente della convalida sia sempre noto piuttosto che capito al momento dell'invio. Questo è un po 'il punto della convalida di Angular. Non è possibile avere alcuna indicazione visiva di uno stato non valido quando l'ambito non lo conosce.
Kevin Beal,

1
Ho provato questo approccio, ma sembra che valuti entrambi (cioè non mette in corto circuito il valore booleano dopo &&che ho provato a passare il valore come parte dell'invio e ha confermato che il valore stesso è "falso"
Archimede Trajano

67

Cambia il pulsante di invio in:

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

1
Bella risposta. Sei forte!
Harsha.Vaswani,

24
Puoi comunque inviare il modulo se premi invio mentre un campo di input ha lo stato attivo!
fabsenet,

2
@Rosso: vedi commento sopra.
Andrei Rînea,

Mentre disabilitare il pulsante è di solito il modo migliore per risolverlo, non è ciò che l'OP ha richiesto.
downhand

1
Combinare questa tecnica per fornire un feedback visivo all'utente insieme alla risposta di @Yashua per impedire l'invio del modulo è perfetto. Grazie!
tkarls,

43

Quindi la risposta suggerita da TheHippo non ha funzionato per me, invece ho finito per inviare il modulo come parametro alla funzione in questo modo:

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

Ciò rende il modulo disponibile nel metodo del controller:

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

Ho avuto lo stesso problema. Utilizzando il tuo metodo ha funzionato, però.
Panda4Man,

Questo è leggermente migliore rispetto alla risposta accettata perché il modulo $ check valido viene eseguito in JS e non in HTML.
cellepo,

Tuttavia, non penso che sia necessario passare loginForm per inviare la funzione: penso che $ scope.loginform dovrebbe essere disponibile in JS (almeno era per me), quindi è possibile sostituire il modulo. $ Valido con $ scope.loginform . $ valida.
cellepo,

13

I moduli vengono automaticamente inseriti in $ scope come oggetto. È possibile accedervi tramite$scope[formName]

Di seguito è riportato un esempio che funzionerà con la configurazione originale e senza dover passare il modulo stesso come parametro in ng-submit.

var controller = function($scope) {

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

        }
    }

};

Esempio di lavoro: http://plnkr.co/edit/BEWnrP?p=preview


4
Come accederesti al modulo se usi la notazione "Come controller" invece di $ scope?
Masimplo,

@masimakopoulos: puoi semplicemente usare if(this.loginform.$invalid).. invece, ma nell'HTML devi dare al modulo il nome <form name="ctrl.loginform" ... E questo presuppone che tu stia usando <div ng-controller="controller as ctrl"..nel tuo controller come sintassi. Grazie @JoshCaroll
Bart

13

HTML:

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

Nel tuo controller:

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

è davvero necessario effettuare il controllo con il metodo onsubmit? Ciò significa che devi verificare che l'input soddisfi tutti i criteri sia nel markup (via angolare) sia nel codice js. A mio avviso, angolare non dovrebbe chiamare onsubmit quando l'input non è valido. vedi benlesh.com/2012/11/angular-js-form-validation.html dicendo "ng-submit non può essere chiamato fino a quando l'intero modulo non è $ valido"
Runar Halse

È inoltre possibile disabilitare il pulsante per non consentire l'invio se il modulo è valido. Puoi anche usare il modulo an ng-submit. Se angolare non gestisce la convalida del modulo, allora event.preventDefault()è la strada da percorrere, per interrompere l'invio del modulo.
TheHippo,

@RunarHalse È davvero necessario fare il controllo. Sono d'accordo con te che non dovrebbe essere così. Il motivo per cui il metodo onsubmit non viene chiamato nell'esempio collegato è perché tale esempio non ha un set novalidate. Il browser impedisce agli eventi di aumentare, non angolari. Ecco il suo esempio w / nobalidate su: plnkr.co/edit/R0C8XA?p=preview . Si noti che il modulo viene inviato.
davidmdem,

perfetto proprio quello che stavo cercando, un modo per bloccare l'invio del modulo usando
angular

3

Sebbene non sia una soluzione diretta per la domanda dei PO, se il tuo modulo si trova in un ng-appcontesto, ma vuoi che Angular lo ignori del tutto, puoi farlo esplicitamente usando la ngNonBindabledirettiva:

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

2

Solo per aggiungere alle risposte sopra,

Avevo 2 pulsanti regolari come mostrato di seguito. (Nessun tipo = "invia" ovunque)

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

Non importa quanto ho provato, premendo invio una volta che il modulo era valido , è stato chiamato il pulsante "Cancella modulo", cancellando l'intero modulo.

Come soluzione alternativa,

Ho dovuto aggiungere un pulsante di invio fittizio che era disabilitato e nascosto. E questo pulsante fittizio doveva trovarsi sopra tutti gli altri pulsanti, come mostrato di seguito .

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

Bene, la mia intenzione non è mai stata quella di inviare su Enter, quindi l'hack sopra indicato funziona bene.


puoi interrompere l'invio premendo premi anche rimuovendo l'attributo on ng-submit dal tuo modulo
Kieran,

1

So che questo è un vecchio thread, ma ho pensato di dare anche un contributo. La mia soluzione è simile al post già contrassegnato come risposta. Alcuni controlli JavaScript in linea sono utili.

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

1
Puoi comunque inviare il modulo se premi invio mentre un campo di input ha lo stato attivo!
Yevgeniy Afanasyev il

0

So che è tardi e mi è stato risposto, ma mi piacerebbe condividere le cose pulite che ho fatto. Ho creato una direttiva ng-validate che aggancia onsubmit del modulo, quindi emette prevent-default se $ eval è falso:

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

Nel tuo html:

<form name="offering" method="post" action="offer" ng-validate="<boolean expression">
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.