Nesse post vamos aprender sobre mais um plugin do knockoutjs: knockout validation. Trata-se de um plugin de validação para trabalhar com o view model do KO. Devemos utilizar o próprio arquivo js do KO e o o arquivo do plugin que pode ser referenciado aqui: http://cdnjs.cloudflare.com/ajax/libs/knockout-validation/1.0.2/knockout.validation.min.js. O plugin faz uso de “extenders” do KO, para entender melhor para que server, e como implementar um customizado leia https://andrebtoe.com/2014/10/15/como-estender-um-observable-no-knockoutjs.
Veja um exemplo mais completo usando o plugin de validação http://jsfiddle.net/andrebtoe/yr508w0c/1
Vamos fazer um exemplo simples, primeiro devemos criar uma classe para ser utilizada como view model:
function ViewModel(){ var self = this; self.Nome = ko.observable().extend({ required: true }); }
Acima definimos que a classe “ViewModel” possui uma propriedade observable, e utiliza um “extender” “required”.
Também devemos inicializar a validação da seguinte maneira:
ko.validation.init(); ko.applyBindings(new ViewModel());
Devemos chamar o método “ko.validation.init” antes do método do KO “ko.applyBindings”, para a validação funcionar corretamente.
Vamos adicionar o html para ver a validação funcionando.
<form> <input type="text" data-bind="value: Nome" /> <input type="submit" value="Enviar" /> </form>
Acima temos apenas uma tag input que vincula a propriedade “Nome”, através do “data-bind”.
Veja funcionando http://jsfiddle.net/andrebtoe/zqeLxdLz/1.
Se você informar alguns espaços no campo, perceberá que uma mensagem será inserida ao lado (não submeta os dados do formulário, explicarei como implementar o submit mais abaixo).
Mensagem
Como podemos visualizar até o momento, a mensagem de “required” é “This field is required”, vamos mudar a mensagem utilizando os parâmetros da validação.
function ViewModel(){ var self = this; self.Nome = ko.observable().extend({ required: { params: true, message: "Preenchimento obrigatório" }}); }
Acima trocamos o valor “true” por um objeto que tem “params” e “message”, em alguns caso o valor de “params” é utilizado como parâmetro de validação, como por exemplo o tipo de validação “min”. O atributo “message” é para definir o texto de validação que deverá ficar visível.
http://jsfiddle.net/andrebtoe/hq8bmwfu
Local da mensagem
Podemos definir o local onde mensagem de erro deve aparecer, para isso devemos criar um elemento html e atrelar a validação, o html deve ficar assim:
<form> <span class="error" data-bind="validationMessage: Nome"></span> <input type="text" data-bind="value: Nome" /> <input type="submit" value="Enviar" /> </form>
Acima definimos que uma tag span deve ficar responsável por mostra a mensagem de erro da propriedade “Nome”, utilizando o “bindingHandler” “validationMessage”. Isso funciona, porem tem um efeito colateral indesejado (mas nem sempre): “A mensagem de erro é exibida 2 vezes, antes e depois da tag input”, veja no exemplo http://jsfiddle.net/andrebtoe/mpkcc4br.
Para ressorvermos esse problema, temos que informar que a mensagem não deve ser exibida em um dos casos
<form> <span class="error" data-bind="validationMessage: Nome"></span> <div data-bind="validationOptions: { insertMessages: false, decorateInputElement: false}"> <input type="text" data-bind="value: Nome" /> </div> <input type="submit" value="Enviar" /> </form>
Colocamos o input envolto de uma tag div, e nela informamos algumas opções de validação, assim todas as validações nesse contexto não devem serem exibidas http://jsfiddle.net/andrebtoe/0aphLbmn.
Submeter os dados
Como citei acima, caso o formulário fosse submetido a validação não funcionaria, pois bem, devemos definir uma propriedade que ficará responsável pela validações, assim saberemos quando podemos submeter ou não. Vamos adicionar a propriedade “Erros” e adicionar um método para validar “EnviarDados”.
function ViewModel(){ var self = this; self.Nome = ko.observable().extend({ required: { params: true, message: "Preenchimento obrigatório" }}); self.Erros = ko.validation.group(self); self.EnviarDados = function(){ if(self.Erros().length == 0) alert("Formulário válido"); else self.Erros.showAllMessages(); } }
Adicionamos a propriedade “Erros” que recebe o retorno o método “ko.validation.group”, com as definições da validação da instancia (this), ele basicamente disponibiliza a quantidade de erros que a instancia possui. E tambem adicionamos o método “EnviarDados”, que por sua vez, vefica a quantidade de erros, caso seja zero, um “alert” é executado, do contrário, é executado o método “showAllMessages”, para mostrar todas as mensagens de erro http://jsfiddle.net/andrebtoe/jgxxku75.
Validação condicional
É possível adicionar uma validação condicional, por exemplo, uma determinada propriedade só deve ser obrigatório caso a propriedade possua valor x. Para o exemplo vamos adicionar uma propriedade no view model, para controlar com um booleano, se o campo é obrigatório ou não, e vamos colocar uma condição na validação de “Nome”, para definir quando validar, utilizando o atributo “onlyIf”
function ViewModel(){ var self = this; self.PossuiNome = ko.observable(true); self.Nome = ko.observable().extend({ required: { params: true, message: "Preenchimento obrigatório", onlyIf: function(){ return self.PossuiNome(); } }}); self.Erros = ko.validation.group(self); self.EnviarDados = function(){ if(self.Erros().length == 0) alert("Formulário válido"); else self.Erros.showAllMessages(); } }
Acimas adicionamos a propriedade “PossuiNome”, que é observable e possui o valor “true” como padrão. E adicionamos o atributo “onlyIf”, na validação “required” de “Nome”. O método sempre deve retornar um valor booleano, parta indicar se deve validar ou não, no nosso caso, estamos retornando apenas o valor da propriedade “PossuiNome”, não houve necessidade de verificar nada. E modificamos o html
<form data-bind="submit: EnviarDados"> <label> Possui nome <input type="checkbox" data-bind="checked: PossuiNome" /> </label> <br /> <label> Nome: <input type="text" data-bind="value: Nome" /> </label> <input type="submit" value="Enviar" /> </form>
Adicionamos a tag input do tipo “checkbox”, para atrelar com a propriedade “PossuiNome”, utilizando o “bindingHandler” “checked”. http://jsfiddle.net/andrebtoe/00583t68.
Outros tipos de validação
Até o momento vimos apenas o tipo “required”, o knockout validation disponibiliza alguns tipos:
Validação | Descrição | Parametros | Exemplo |
---|---|---|---|
Required | Define obrigatoriedade para propriedade. |
ko.observable().extender({ requird: true }); |
|
Min | Define um número minimo para ser utilizado. | Número minimo |
ko.observable().extender({ min: 4 }); |
Max | Define um número máximo para ser utilizado. | Número máximo |
ko.observable().extender({ max: 4 }); |
MinLength | Define um número de caracteres minimo para ser utilizado. | Número minimo |
ko.observable().extender({ minLength: 4 }); |
MaxLength | Define um número de caracteres máximo para ser utilizado. | Número máximo |
ko.observable().extender({ maxLength: 4 }); |
Pattern | Define uma expressão regular para ser utilizada. | Expressão regular |
ko.observable().extender({ pattern: /^[0-9]$/ }); |
Date | Define uma data válida para ser utilizada. |
ko.observable().extender({ date: true }); |
|
Define um e-mail válido para ser utilizado. |
ko.observable().extender({ email: true }); |
||
Equal | Define o valor que deve ser utilizado exatamente. | Valor |
ko.observable().extender({ equal: "Olá" }); |
NotEqual | Define o valor que não deve ser utilizado exatamente. | Valor |
ko.observable().extender({ notEqual: "Olá" }); |
Number | Define um valor numérico para ser utilizado. |
ko.observable().extender({ number: true }); |
Podemos utilizar qualquer um dos tipos de validação da tabela acima.
Novo tipo de validação
Podemos criar um novo tipo a ser utilizado para validação. Vamos adicionar o tipo url
ko.validation.rules["url"] = { validator: function (val, required) { if (!val) { return !required } val = val.replace(/^\s+|\s+$/, ''); return val.match(/^(?:(?:https?|ftp):\/\/)(?:\S+(?::\S*)?@)?(?:(?!10(?:\.\d{1,3}){3})(?!127(?:\.\d{1,3}){3})(?!169\.254(?:\.\d{1,3}){2})(?!192\.168(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]+-?)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]+-?)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,})))(?::\d{2,5})?(?:\/[^\s]*)?$/i); }, message: "URL inválida" };
No código acima definimos o nome da validação “url”, e passamos um objeto com o parâmetro, onde temos o atributo “validator”, que recebe uma função com dois parâmetros, o primeiro retorna o valor da propriedade que está sendo validada, e o segundo o valor de “params”. Já na implementação, verificamos se o valor da propriedade está definido, caso não esteja, o segundo parâmetro é considerado para validar. Caso a propriedade possua um valor definido, validamos o valor com uma expressão regular. o Atributo “message” define a mensagem padrão da validação, que pode ser redefinida quando utilizada http://jsfiddle.net/andrebtoe/u52dndz0.
Um tipo de validação que não é implementado pelo plugin, e seu uso é recorrente é o “remote”, vamos ver como adicionar.
ko.validation.rules["remote"] = { async: true, validator: function (val, parms, callback) { var defaults = { type: "POST", success: callback }; var options = $.extend(defaults, parms); $.ajax(options); this.message = options.mens; }, message: "" };
Como a intenção da validação é executar um ajax (estamos utilizando o jQuery para esse fim), é necessário definir o atributo “async” como “true”, assim a requisição se torna assíncrona, para o plugin.
Personalizar validação
Podemos mudar algumas configurações padrões do plugin, para isso devemos chamar o método “ko.validation.configure”, antes do “ko.applyBindings”, temos:
ko.validation.configure({ registerExtenders: true, messagesOnModified: true, decorateElementOnModified: true, errorElementClass: 'error', errorMessageClass: 'error', grouping: { deep: true, observable: true } });
Os dois atribuitos de grouping tem o valor “false” como padrão.
Atributo | Descrição |
---|---|
registerExtenders | Define que as novas validações serão registradas automaticamente. |
messagesOnModified | Indica se as mensagens de validação são acionados apenas quando as propriedades observables são modificadas ou em todos os momentos. |
decorateElementOnModified | Indica se deve adicionar uma classe (no nosso casso: ‘error’, isso pode ser visto no atributo “errorElementClass”) ao input atrelado. |
errorElementClass | Classe do css que deve ser atribuída ao elemento atrelado a propriedade observable, caso o atributo “decorateElementOnModified” seja “true”. |
errorMessageClass | Classe do css que deve ser definida a mensagem de erro. |
grouping | É possível determinar se a validação deve ser feita apenas em um nível, ou validar as propriedade recursivamente com: * deep: Valida em profundidade, todos os sub níveis de instancia do view model * observable: Indica que as propriedade deve ser simples ou computadas. |
Quando se utiliza o método “ko.validation.configure”, não é necessário chamar “ko.validation.init”, Veja um exemplo http://jsfiddle.net/andrebtoe/0t2p0hyL
Até a próxima pessoal!
Olá, estou iniciando a utilização deste plugin de validação, porém quando coloco o ko.validation.configure recebo a mensagem no console de navegador de que esta função não existe.
Complementando: Baixei a versão que está neste git https://github.com/Knockout-Contrib/Knockout-Validation através do NuGet do Visual Studio.
Quando uso o ko.validation.init() funciona tranquilamente.
Encontrei a resposta aqui: https://github.com/Knockout-Contrib/Knockout-Validation/wiki/Configuration
Deve ser uma versão atualizada.