AngularJS verifica se o formulário é válido no controlador

86

Preciso verificar se um formulário é válido em um controlador.

Visão:

<form novalidate=""
      name="createBusinessForm"
      ng-submit="setBusinessInformation()"
      class="css-form">
 <!-- fields -->
</form>

No meu controlador:

.controller(
    'BusinessCtrl',
    function ($scope, $http, $location, Business, BusinessService, 
              UserService, Photo)
    {

        if ($scope.createBusinessForm.$valid) {
            $scope.informationStatus = true;
        }

        ...

Estou recebendo este erro:

TypeError: Cannot read property '$valid' of undefined
Rober
fonte
Você envolveu a função setBusinessInformation no controlador?
matsko de
3
código muito fragmentado para analisar o que pode estar errado ... crie uma demonstração simples no jsfiddle.net ou plunker que replica o problema. O formulário está dentro do escopo de BusinessCtrl? não posso dizer sem ver mais
charlietfl
@matsko: Não. Eu preciso executar este código na inicialização do controlador.
Rober de
@charlietfl: Não há muito mais. Eu removo algum código para simplificar o exemplo. Sim, o formulário deve estar no escopo do BusinessCtrl (o controlador é definido em rotas no app.js. Eu adiciono minha solução na resposta abaixo. Mas, não sei por que não está funcionando dessa forma.
Rober

Respostas:

109

Tente isto

em vista:

<form name="formName" ng-submit="submitForm(formName)">
 <!-- fields -->
</form>

no controlador:

$scope.submitForm = function(form){
  if(form.$valid) {
   // Code here if valid
  }
};

ou

em vista:

<form name="formName" ng-submit="submitForm(formName.$valid)">
  <!-- fields -->
</form>

no controlador:

$scope.submitForm = function(formValid){
  if(formValid) {
    // Code here if valid
  }
};
Damsoriano
fonte
E se eu quiser validar vários botões em um formulário?
Fahad Mullaji
isso funcionou para mim, mas por que $scope.formName.$validresulta em indefinido?
ps0604
Se você usar ng-if então $ scope.formName. $ Valid não funcionará e se você usar ng-show então $ scope.formName. $ Valid funcionará.
Vaibhav Shaha
2
Esta deve ser a melhor resposta, simples. Mas você poderia lidar com o formulário inválido? Como você poderia mostrar ao usuário quais entradas são inválidas?
Nicolas Leucci
1
@ ps0604 o formName.$validpode ser acessado apenas no template, se você deseja acessar no controlador você precisa criar um objeto para esse gosto $scope.forms.formNamee no template: <form name="forms.formName"> verifique este comentário
Damsorian 23/09/16
29

Eu atualizei o controlador para:

.controller('BusinessCtrl',
    function ($scope, $http, $location, Business, BusinessService, UserService, Photo) {
        $scope.$watch('createBusinessForm.$valid', function(newVal) {
            //$scope.valid = newVal;
            $scope.informationStatus = true;
        });
        ...
Rober
fonte
Lembre-se também disso - Se o formulário for Modal, lembre-se de declarar o nome do formulário como notação de ponto, por exemplo: "data.theform" e acesse-o em seu controlador como $ scope.data.theform
Jasper
2
Isso não funciona para mim. Por favor, mostre como você coloca 'createBusinessForm' no escopo $ do controlador.
cyrf
As coisas de $ scope se foram, agora que estamos usando a vmabordagem. você pode criar um plunker para a mesma resposta usando o controlador como abordagem de sintaxe. Eu não sou capaz de fazer isso. Será útil também para outros que estão procurando uma resposta no contexto de hoje. Obrigado
ankitd de
14

Aqui está outra solução

Defina uma variável de escopo oculta em seu html, então você pode usá-la em seu controlador:

<span style="display:none" >{{ formValid = myForm.$valid}}</span>

Aqui está o exemplo de trabalho completo:

angular.module('App', [])
.controller('myController', function($scope) {
  $scope.userType = 'guest';
  $scope.formValid = false;
  console.info('Ctrl init, no form.');
  
  $scope.$watch('myForm', function() {
    console.info('myForm watch');
    console.log($scope.formValid);
  });
  
  $scope.isFormValid = function() {
    //test the new scope variable
    console.log('form valid?: ', $scope.formValid);
  };
});
<!doctype html>
<html ng-app="App">
<head>
 <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/angularjs/1.2.1/angular.min.js"></script>
</head>
<body>

<form name="myForm" ng-controller="myController">
  userType: <input name="input" ng-model="userType" required>
  <span class="error" ng-show="myForm.input.$error.required">Required!</span><br>
  <tt>userType = {{userType}}</tt><br>
  <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br>
  <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br>
  <tt>myForm.$valid = {{myForm.$valid}}</tt><br>
  <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br>
  
  
  /*-- Hidden Variable formValid to use in your controller --*/
  <span style="display:none" >{{ formValid = myForm.$valid}}</span>
  
  
  <br/>
  <button ng-click="isFormValid()">Check Valid</button>
 </form>
</body>
</html>

Enkode
fonte
4

O BusinessCtrlé inicializado antes do createBusinessForm's FormController. Mesmo se você tiver o ngControllerno formulário, não funcionará da maneira que você queria. Você não pode evitar isso (você pode criar o seu ngControllerDirectivee tentar enganar a prioridade). É assim que o angularjs funciona.

Consulte este plnkr por exemplo: http://plnkr.co/edit/WYyu3raWQHkJ7XQzpDtY?p=preview

Oliver
fonte