A maioria dos dados de entrada do usuário relacionados podem ser coletados no HTML5 <form>
.
O Angular reescreve a form
diretiva, faz com que tenha um mecanismo holístico de validação, para que o usuário possa ser notificado de entradas inválidas por exemplo. Se quisermos usar esses recursos do Angular, devemos usar alguns atributos específicos ao lado de form
e sua subtag.
Com base em nosso aplicativo da Web de biblioteca pública, tomamos a função de
Add a book
como um exemplo para apresentar a validação do caminho angular.
Como dissemos, todas as entradas do usuário serão compactadas <form>
, aqui está o formato básico da form
tag HTML5 no Angular:
<form name="bookInfo" novalidate="novalidate" ng-submit="createBook()">
...
</form>
novalidate
é usado para desabilitar a validação de formulário nativo do navegador, pois cada navegador pode ter sua própria maneira de lidar com a validação de formulário. Não é isso que esperamos.
Observe que o form
não é mais a tag HTML5 original, ele foi substituído por Angular e possui um alias ngForm
. O que significa que os dois formatos a seguir são iguais:
1. <form name="bookInfo">...</form>
2. <ng-form name="bookInfo">...</ng-form>
form
em Angular é rastreado por form.FormController
, que continua observando o estado do formulário, como sendo válido / inválido. Além disso, quando o name
atributo de <form>
for especificado, o formulário será publicado no escopo atual com este nome.
Restrições e validações genéricas
- O formulário
name
é “bookInfo”;- Um livro tem quatro atributos: ISBN, Título, Ano e Edição. Fazemos cada um como um
input
elemento para receber as entradas do usuário.- Cada entrada possui um
ngModel
atributo, será controlada pelo Angular como modelo.
Nosso foco é input
neste momento. O Angular fornece muitos argumentos input
para vinculação de dados, controle de estado e validação:
- Valor Obrigatório
- Restrição:
<input type="text" name="isbn" ng-model="book.isbn" required="required" />
- Validação:
bookInfo.isbn.$error.required
- Descrição: a entrada de ngModel é necessária, não deve estar vazia, caso contrário, o Angular lançará um erro, o valor de será verdadeiro.
book.isbn
bookInfo.isbn.$error.required
- Restrição:
- padronizar
- Restrição:
<input type="text" name="isbn" ng-model="book.isbn" ng-pattern="/\b\d{9}(\d|X)\b/" />
- Validação:
bookInfo.isbn.$error.pattern
- Descrição: a entrada de ngModel deve atender ao padrão, caso contrário, o Angular lançará um erro, o valor de será verdadeiro.
book.isbn
/\b\d{9}(\d|X)\b/
bookInfo.isbn.$error.pattern
- Restrição:
- Comprimento da corda
- Restrição:
<input type="text" name="title" ng-model="book.title" ng-maxlength="50" />
- Validação:
bookInfo.title.$error.maxlength
- Descrição: o comprimento da string de entrada de ngModel deve ser menor que 50, caso contrário, Angular gerará um erro, o valor de será verdadeiro.
book.title
bookInfo.title.$error.maxlength
- Restrição:
- Alcance
- Restrição:
<input type="number" name="year" ng-model="book.year" min="1459" max="{{currentYear}}" />
- Validação:
bookInfo.year.$error.number && bookInfo.year.$error.min && bookInfo.year.$error.max
- Descrição: a entrada de ngModel deve ser um número, o número também deve estar entre 1459 e o ano atual (fale sobre isso mais tarde), caso contrário, o Angular lançará o erro correspondente.
book.year
- Restrição:
Além disso, para permitir o estilo da forma, ngModel
irá adicionar automaticamente algumas classes CSS:
ng-valid
: a entrada é válidang-invalid
: a entrada é inválidang-touched
: o campo de entrada foi borradong-untouched
: o campo de entrada não foi desfocadong-pending
: qualquer um$asyncValidators
está incompleto- …
Além disso, o form
também possui alguns atributos para a validação holística do estado. Tomamos o mais útil $invalid
como exemplo:
<form name="bookInfo" ng-submit="createBook()">
...
<input type="submit" ng-disabled="bookInfo.$invalid" />
</form>
Quando todas as entradas que pertencem a este formulário forem válidas, o valor de será falso (ao mesmo tempo, seria verdadeiro), então todos os dados podem ser enviados.bookInfo.$invalid
bookInfo.$valid
Restrições e validações específicas (Costom)
A restrição e validação genéricas podem resolver a maioria dos requisitos comuns. Mas quando ele não consegue resolver seus problemas, o Angular oferece outra opção – a diretiva personalizada . Com uma diretiva personalizada, podemos adicionar nossas próprias funções de validação ao objeto $validators
ou $asyncValidators
no ngModelController
.
Valor calculado
Anteriormente, implementamos a restrição e validação do ano. A faixa de max é um valor dinâmico que deve ser aumentado a cada ano. Se não quisermos assumir a tarefa de alterar o valor por nós mesmos, é melhor deixar o computador ir assim.
Maneira simples
Como nosso exemplo, definimos uma expressão como o valor do atributo. Sabemos que pode obter o valor do ano atual, então o colocamos no controlador e o atribuímos ao escopo como . Angular levará o valor para o atributo.{{currentYear}}
max
new Date().getFullYear()
$scope.currentYear = new Date().getFullYear();
Melhor maneira
O primeiro método é fácil e rápido, mas vai misturar a estrutura de nossa aplicação web. O problema de um DOM deve ser melhor resolvido no lado do template, e este é exatamente o propósito de implementar as diretivas Angular.
As diretivas Angular são marcadores em um elemento DOM (como um atributo, nome de elemento, comentário ou classe CSS) que informam ao compilador HTML do Angular (é como anexar ouvintes de evento ao HTML para torná-lo interativo) para anexar um comportamento específico a esse Elemento DOM ou mesmo transformar o elemento DOM e seus filhos.
Modificamos um pouco nossa definição original de campo de entrada HTML sobre o ano:
<input type="number" name="year" ng-model="book.year" year-period="year-period" />
Aqui, a diretiva Angular é definida pelo usuário. Seria implementado para restringir o ano de publicação do livro – não antes de 1459 e não depois do ano atual:year-period
app.directive('yearPeriod', function() {
return {
restrict: 'A', // the directive will only match attribute name
require: 'ngModel', // the directive require the ng-model
link: function(scope, element, attribute, ngModel) { // "link" is defined by Angular to modify the DOM
ngModel.$validators.yearPeriod = function(modelValue, viewValue) { // “$validators” is a property of ngModelController, also a collection of validators that are applied whenever the model value changes.
var minYear = 1459; // Minimal publish year is 1459
var maxYear = new Date().getFullYear(); // Maximal publish year is this year
if (modelValue < 1459 || modelValue > maxYear) {
return false; // return to DOM a boolean value “bookInfo.year.$error.yearPeriod === true”
} else {
return true; // return to DOM a boolean value “bookInfo.year.$error.yearPeriod === false”
}
}
}
};
});
Valor Único
Armazenamos livros em nosso aplicativo da web, e cada livro tem um valor obrigatório ISBN , o que significa que em nossa biblioteca não deve haver dois ou mais livros com o mesmo isbn. O ISBN deve ser o valor único.
Definimos a entrada de isbn primeiro:
<input type="text" name="isbn" ng-model="book.isbn" ng-pattern="/\b\d{9}(\d|X)\b/" required="required" unique-isbn="unique-isbn" />
Semelhante à Diretiva de Valor Calculado criada acima, percebemos aqui apenas um XMLHTTPRequest assíncrono ao nosso armazenamento em nuvem Parse, que irá verificar o banco de dados, se houver um livro com o mesmo ISBN ou não, após o usuário preencher o campo de entrada do ISBN. Um valor booleano “bookInfo.isbn. $ Error.uniqueIsbn === true” será retornado, se o ISBN existir no banco de dados.
publicLibraryDirectives.directive('uniqueIsbn', ['$q', '$timeout', '$http', function($q, $timeout, $http) {
return {
restrict: 'A',
require: 'ngModel',
link: function(scope, element, attribute, ngModel) {
ngModel.$asyncValidators.uniqueIsbn = function(modelValue, viewValue) {
var defer = $q.defer(); // $q.defer() is used to expose the associated Promise for signaling the successful or unsuccessful completion as well as the status of the task
$timeout(function() { // $timeout is Angular’s wapper for window.setTimeout
$http({ // Send a GET request to Parse.com
method: 'GET',
url: 'https://api.parse.com/1/classes/Book',
params: {
where: {'isbn': modelValue}
},
headers:{
'X-Parse-Application-Id': Application_ID,
'X-Parse-REST-API-Key': REST_API_Key,
}
})
.success(function(data, status, headers, config){ // When request is success, get response message from server
if (data.results.length === 0) { // If there is no same ISBN in the database, the response’s array should be null
defer.resolve();
} else { // otherwise the ISBN exists
defer.reject();
}
})
.error(function(data, status, headers, config){ // The connection with database went wrong
console.log("something went wrong...");
});
}, 2000); // Set a time delay
return defer.promise; // return a boolean value to view side after finished the XMLHTTPRequest
}
}
};
}]);
Maneira diferente de exibir mensagens de erro
Nesta etapa, avançamos em direção às diferentes maneiras de exibir mensagens de erro na visualização.
O Angular oferece várias soluções, ou melhor, diretivas para lidar com essa tarefa, os formulários populares são ngShow
, ngIf
e uma nova diretiva ngMessages
no Angular v1.3.x
Discutimos muito sobre as restrições de entrada e validações acima; lembre-se de que o Angular retornará um valor booleano para uma variável definida pelo sistema para cada validação que depende da restrição.
ngModel.$error
ngModel
Para a comparação a seguir, usamos o campo de entrada do ano como exemplo:
<input type="number" name="year" ng-model="book.year" year-period="year-period" required="required" />
A entrada de ngModel é necessária, o valor deve ser um número e o número não deve ser inferior a 1459 ou superior a 2015 (ano atual como um número).book.year
ng-show
A ngShow
diretiva mostra ou oculta o elemento HTML fornecido com base na expressão fornecida ao ngShow
atributo. O elemento é mostrado ou oculto removendo ou adicionando a classe CSS ao elemento. Portanto, a verdade é que o conteúdo deste elemento será carregado com a página da web, e o CSS controlá-lo-á para aparecer ou ficar oculto..ng-hide
Exibir mensagens de erro usando ngShow
:
<input type="number" name="year" ng-model="book.year" year-period="year-period" required="required" />
<span ng-show="bookInfo.year.$error.required">Year is required.</span>
<span ng-show="bookInfo.year.$error.number">Not valid number.</span>
<span ng-show="bookInfo.year.$error.yearPeriod">The publish time should be between 1459 and this year.</span>
Quando a página for carregada, todas span
também serão carregadas, e podemos ver seu conteúdo “O ano é obrigatório”. existia apenas porque o Angular detecta que atualmente o campo de entrada está vazio ou melhor, o valor de é verdadeiro, então o conteúdo dentro de deve aparecer. Depois de colocarmos algumas letras no campo, “O ano é obrigatório”. ficará oculto.bookInfo.year.$error.required
span
O span
atributo with e são semelhantes ao atributo with .ng-show="bookInfo.year.$error.number"
ng-show="bookInfo.year.$error.yearPeriod"
span
ng-show="bookInfo.year.$error.required
Observe que o span
está apenas oculto, mas ainda existe no DOM. Esta é exatamente a parte diferente entre ngShow
e ngIf
.
ng-if
A ngIf
diretiva remove ou recria uma parte da árvore DOM com base em uma expressão. Se a expressão atribuída a for ngIf
avaliada como um valor falso, o elemento será removido do DOM, caso contrário, um clone do elemento será reinserido no DOM.
Exibir mensagens de erro usando ngIf
:
<input type="number" name="year" ng-model="book.year" year-period="year-period" required="required" />
<span ng-if="bookInfo.year.$error.required">Year is required.</span>
<span ng-if="bookInfo.year.$error.number">Not valid number.</span>
<span ng-if="bookInfo.year.$error.yearPeriod">The publish time should be between 1459 and this year.</span>
Quando a página é carregada, podemos ver seu conteúdo “O ano é obrigatório”. existia. Parece que está usando ngShow
porque atualmente o valor de é true, fez um clone de e inseriu no DOM, de modo que o conteúdo dentro de é mostrado. Depois de colocarmos algumas letras no campo, o valor de seria falso e removerá o para que “Ano seja obrigatório”. vai desaparecer.bookInfo.year.$error.required
ngIf
span
span
bookInfo.year.$error.required
ngIf
span
O span
atributo with e são semelhantes ao atributo with .ng-if="bookInfo.year.$error.number"
ng-if="bookInfo.year.$error.yearPeriod"
span
ng-if="bookInfo.year.$error.required"
ngIf
controla o elemento que é parte da árvore DOM enquanto ngShow
altera o comportamento do site via uma propriedade CSS.
Por outro lado, uma vez que todas as diretivas correspondentes ao elemento DOM tenham sido identificadas, o compilador Angular classificará as diretivas por sua prioridade . ngIf
tem uma das prioridades mais altas (nível 600 por padrão), ele será executado primeiro, antes de todas as outras diretivas de prioridade inferior. E se o usarmos em vez de ngShow
, a IU será bem acelerada [^ 1].
[^ 1]: Não encontrei uma ferramenta para testar a velocidade, a informação veio de um post de stackoverflow de gjoris .
ng-messages
O ngMessages
é um módulo Angular publicado pela versão 1.3.x do Angular. Ele contém ngMessages
e ngMessage
diretrizes. Ele fornece especificamente suporte aprimorado para a exibição de mensagens, como mensagens de erro, nos modelos. Em vez de depender de instruções complexas em nosso modelo de formulário para mostrar e ocultar mensagens de erro específicas para o estado de um campo de entrada.ng-if
As tarefas de duas diretivas são:
ngMessages
: foi projetado para mostrar e ocultar mensagens com base no estado de um objeto de chave / valor que ele escuta, e a própria diretiva complementa o relatório de mensagem de erro com o$error
objeto. Por padrão, apenas uma mensagem será exibida por vez, mas isso pode ser alterado usando no contêiner de diretiva. E usando o modelo especificado pode ser incluído no contêiner ng-messages.ng-messages-multiple
ng-messages-include
ngMessage
: tem como objetivo mostrar e ocultar uma determinada mensagem. ParangMessage
operar, umangMessages
diretiva pai em um elemento DOM pai deve ser situada, uma vez que determina quais mensa