Angularjs предотвращает отправку формы при сбое проверки ввода

155

Я пишу простую форму входа в систему, используя angularjs с некоторой проверкой ввода на стороне клиента, чтобы проверить, что имя пользователя и пароль не пусты и длиннее трех символов. Смотрите ниже код:

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

И контроллер:

var controller = function($scope) {

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

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

};

Проблема заключается в том, что login.submitфункция будет вызываться, даже если ввод неверен. Можно ли предотвратить такое поведение?

В качестве примечания могу упомянуть, что я использую также bootstrap и requirejs.

Рунар Халс
источник
мы можем использовать его без тега формы и все же form.valid будет работать по щелчку мышью!
Ризван Патель

Ответы:

329

Ты можешь сделать:

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

Нет необходимости в проверках контроллера.

cyberwombat
источник
8
Это должен быть принятый ответ. Не нужно ничего проверять в контроллере
Howie
10
Я не согласен с «нет необходимости проверок контроллера». Что если мы добавим дополнительные проверки в функцию submit.
SlaterCodes
6
Выполните дополнительную проверку в директиве. Обновите проверку с помощью $ setValidity.
TMB
@ b1tsh1ft Было бы предпочтительно, чтобы текущее состояние проверки всегда было известно, а не выяснялось при отправке. В этом вся суть ангулярной проверки. Вы не можете иметь никаких визуальных указаний на недопустимое состояние, когда область не знает об этом.
Кевин Бил
1
Я пробовал этот подход, но кажется, что он оценивает оба (то есть он не замыкает логическое значение после того, как &&я попытался передать значение как часть подтверждения и подтвердил, что само значение равно «false»)
Архимед Траяно
67

Измените кнопку отправки на:

<button type="submit" ng-disabled="loginform.$invalid">Login</button>
Bijan
источник
1
Отличный ответ. Ты жжешь!
Harsha.Vaswani
24
Вы все еще можете отправить форму, если нажмете клавишу ввода, когда поле ввода имеет фокус!
fabsenet
2
@Red: см. Комментарий выше.
Андрей Ринея
Хотя отключение кнопки обычно является лучшим способом решения этой проблемы, это не то, о чем просил ОП.
сварки в нижнем положении
1
Идеально сочетать эту технику для обеспечения визуальной обратной связи для пользователя вместе с ответом @Yashua для предотвращения отправки формы. Спасибо!
tkarls
43

Таким образом, предложенный ответ от TheHippo у меня не сработал, вместо этого я отправил форму в качестве параметра функции следующим образом:

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

Это делает форму доступной в методе контроллера:

$scope.login = {
    submit : function(form) {
        if(form.$valid)....
    }
Рунар Халс
источник
Я была такая же проблема. Использование вашего метода сработало, хотя.
Panda4Man
Это немного лучше, чем Принятый ответ, потому что проверка form. $ Valid выполняется в JS, а не в HTML.
виолончель
Однако я не думаю, что вам нужно передавать loginForm для отправки функции: я думаю, что $ scope.loginform должен быть доступен в JS (по крайней мере, для меня), так что вы можете заменить form. $ Valid на $ scope.loginform . $ в силе.
виолончель
13

Ваши формы автоматически помещаются в $ scope как объект. Доступ к нему можно получить через$scope[formName]

Ниже приведен пример, который будет работать с вашей первоначальной настройкой и без необходимости передавать саму форму в качестве параметра в ng-submit.

var controller = function($scope) {

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

        }
    }

};

Рабочий пример: http://plnkr.co/edit/BEWnrP?p=preview

davidmdem
источник
4
Как бы вы получили доступ к форме, если бы вы использовали нотацию «Как контроллер» вместо $ scope?
Masimplo
@masimakopoulos: Вы можете просто использовать if(this.loginform.$invalid).. вместо этого, но тогда в HTML вы должны дать форме имя <form name="ctrl.loginform" ... И это при условии, что вы используете <div ng-controller="controller as ctrl"..в своем контроллере как синтаксис. Спасибо @JoshCaroll
Барт
13

HTML:

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

В вашем контроллере:

$scope.login = {
    onSubmit: function(event) {
        if (dataIsntValid) {
            displayErrors();
            event.preventDefault();
        }
        else {
            submitData();
        }
    }
}
TheHippo
источник
действительно ли необходимо выполнять проверку в методе onsubmit? Это будет означать, что вы должны проверить, что входные данные соответствуют всем критериям как в разметке (через угловой), так и в коде js. По моему мнению, angular не должен вызывать onsubmit, когда ввод неверен. см. benlesh.com/2012/11/angular-js-form-validation.html о том, что «ng-submit нельзя вызывать, пока вся форма не будет $ valid»
Runar Halse
Вы также можете отключить кнопку, чтобы запретить отправку, если форма действительна. Вы также можете использовать форму ng-submit. Если angular не обрабатывает проверку формы, то event.preventDefault()есть способ остановить отправку формы.
TheHippo
@RunarHalse Это действительно необходимо сделать проверку. Я согласен с вами, что так не должно быть. Причина, по которой метод onsubmit не вызывается в примере, который вы связали, заключается в том, что в этом примере не установлен novalidate. Браузер предотвращает подъем событий, а не Angular. Вот его пример с nobalidate: plnkr.co/edit/R0C8XA?p=preview . Обратите внимание, что форма отправляет.
Давидмдем
идеально подходит то, что я искал, способ блокировать
отправку
3

Хотя это и не прямое решение вопроса OP, если ваша форма находится в ng-appконтексте, но вы хотите, чтобы Angular полностью ее игнорировал, вы можете сделать это явно, используя ngNonBindableдирективу:

<form ng-non-bindable>
  ...
</form>
Ян Кларк
источник
2

Просто чтобы добавить к ответам выше,

У меня были 2 обычные кнопки, как показано ниже. (No type = "submit" в любом месте)

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

Независимо от того, сколько я пытался, нажав клавишу ввода после того, как форма была действительной , была вызвана кнопка «Очистить форму», очистив всю форму.

В качестве обходного пути,

Мне пришлось добавить фиктивную кнопку отправки, которая была отключена и скрыта. И эта фиктивная кнопка должна быть поверх всех других кнопок, как показано ниже .

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

Ну, я никогда не собирался отправлять на Enter, так что вышеупомянутый взлом просто отлично работает.

vighnu
источник
Вы также можете прекратить
Kieran
1

Я знаю, что это старая ветка, но я тоже хотел бы внести свой вклад. Мое решение похоже на пост, уже помеченный как ответ. Некоторые встроенные проверки JavaScript делают свое дело.

ng-click="form.$invalid ? alert('Please correct the form') : saveTask(task)"
Дэйв Рассел
источник
1
Вы все еще можете отправить форму, если нажмете клавишу ввода, когда поле ввода имеет фокус!
Евгений Афанасьев
0

Я знаю, что уже поздно, и мне ответили, но я хотел бы поделиться тем, что я сделал. Я создал директиву ng-validate, которая перехватывает отправку формы, а затем выдает предотвратитель по умолчанию, если $ eval имеет значение false:

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

В вашем HTML:

<form name="offering" method="post" action="offer" ng-validate="<boolean expression">
Ран Коэн
источник