Helpers para formulários

Os helpers vão nos permitir criar campos para construir um formulário de uma maneira muito cômoda.

Por Eduard Tomás - Tradução CRV


Publicado em: 17/5/12
Valorize este artigo:
No artigo anterior vimos o uso de POST em ASP.NET MVC junto com as bases do Model Binding. Especificamente, a norma mais importante que devemos lembrar é que o atributo name do campo deve chamar-se igual à propriedade que queremos lincar. É claro que o Model Binder admite lincar parâmetros complexos (uma classe que tenha uma propriedade que seja uma lista de objetos que por sua vez tenham mais propriedades simples ou complexas) e neste caso basta que os atributos name dos campos do formulário sigam determinadas regras. Não vamos entrar em mais detalhe porque, por sorte, o framework nos oferece uma ajuda para não termos que recordar exatamente todas essas regras: os helpers para formulários.

Os helpers vão nos permitir criar campos para construir um formulário de uma maneira muito cômoda e são, sem dúvida, a maneira preferida para fazê-lo.

Criar campos HTML

O primeiro que vamos ver é como criar um campo HTML para editar (ou mostrar) uma propriedade específica do Viewmodel que recebe a visão. Vamos supor que temos essa classe:

public class Trabalhador
{
public string Nome { get; set; }
public string Sobrenome { get; set; }
public DateTime DataNascimento { get; set; }
public double Saldo { get; set; }
public bool EFixo { get; set; }
}

Agora vamos criar uma visão que mostre quatro campos de texto (para nome, sobrenome, data de nascimento e saldo) e uma casa de verificação para indicar se é fixo ou não. Porém em lugar de criar os controles à mão (<input type="xxx">) vamos usar os helpers:

@using MvchelpersForms.Models
@model Trabalhador

<form method="post">

Nome: @Html.TextBoxFor(x=>x.Nome) <br />
Sobrenome: @Html.TextBoxFor(x=>x.Sobrenome) <br />
Data Nascimento: @Html.TextBoxFor(x=>x.DataNascimento) <br />
Saldo: @Html.TextBoxFor(x => x.Saldo) <br />
É Fixo: @Html.CheckBoxFor(x=>x.EFixo) <br />

<input type="submit" value="Enviar"/>

</form>

Estamos usando os helpers:

  • Html.TextBoxFor que mostra um campo de texto para a propriedade indicada
  • Html.CheckBoxFor que mostra uma casa de verificação para a propriedade indicada
Observem como se indica a cada helper para que propriedade deve renderizar o controle:

@Html.TextBoxFor(x=>x.Nome)

O parâmetro em forma x=>x.Nome é uma expressão lambda. Não é objetivo deste artigo entrar nas expressões lambda, assim que nos vamos limitar a indicar que neste caso são usadas para indicar a propriedade. A vantagem de usar uma expressão lambda ao invés de uma cadeia (algo como TextBoxFor("Nome")) é que as expressões lambda são avaliadas em tempo de compilação e não de execução (se nos equivocamos no nome da propriedade o código não compila). Isto requer que a visão seja tipada com o tipo de ViewModel (observem o uso da diretiva @model).

Bem, agora vejamos que código fonte esta visão nos gerou:

<form method="post">

Nome: <input id="Nome" name="Nome" type="text" value="" /> <br />
Sobrenome: <input id="Sobrenome" name="Sobrenome" type="text" value="" /> <br />
Data Nascimento: <input id="DataNascimento" name="DataNascimento" type="text" value="" /> <br />
Saldo: <input id="Saldo" name="Saldo" type="text" value="" /> <br />
É Fixo: <input id="EFixo" name="EFixo" type="checkbox" value="true" /><input name="EFixo" type="hidden" value="false" /> <br />

<input type="submit" value="Enviar"/>

</form>

A verdade é que não se diferencia muito do código que colocaríamos manualmente (que vimos no artigo anterior). O que sim pode chamar a atenção é o campo hidden cujo name é "EFixo". Este campo existe para? bom, para lutar com o fato de que uma checkbox não marcada, não seja enviada. Ou seja, se temos o campo:

<input id="EFixo" name="EFixo" type="checkbox" value="true" />

Isso significa que se a checkbox está marcada se enviará o valor indicado em value (true), enquanto que se a checkbox não está marcada o navegador não enviará nada. Uma checkbox não marcada é como se não existisse. Porém, o Model Binder de ASP.NET MVC vai esperar que haja um campo EFixo para poder conectá-lo à propriedade, daí que se acrescente este campo hidden com o mesmo nome e valor false. Deste modo, se a checkbox não está marcada, o campo hidden é enviado e tem o valor de false. Você teria pensado nisso? Essas são as vantagens de usar os helpers :)

Vantagens de usar os helpers

Porém, ainda há mais, se vocês mostrarem a visão no navegador e sem introduzir dados apertam Enviar:

Exatamente! Aparecem erros. Em concreto o sistema nos mostra um erro se DataNascimento ou Saldo estão vazios. E por que esses dois campos e não os outros? Muito simples: porque esses dois campos estão declarados como DateTime e double que são tipos por valor e portanto nunca podem valer null.

Agora? tentem inserir uma cadeia no Saldo:

Continua dando erro! Isto é porque a cadeia ?dsddsd? não pode ser convertida em double, o que gera um erro.

Agora, quero deixar uma coisa bem clara: O sistema sempre realiza essas validações independente de usarmos os helpers ou não. Estes últimos, porém, estão preparados para mostrar o erro (usar uma classe CSS específica), caso exista.

Agora igual surge a seguinte dúvida: E se não uso os helpers como posso saber se há erros em um campo específico? Pois fazendo o mesmo que de verdade eles fazem: Acessar a propriedade ModelState do ViewData que entre outras coisas contém os erros vinculados a uma propriedade. Vejam como seria o código se queremos gerar o campo Saldo para que se comporte igual que usando o helper:

<input type="text" name="Saldo" value="@(Model != null ? Model.Saldo.ToString() : string.Empty)"
class="@(ViewData.ModelState.ContainsKey("Saldo") && ViewData.ModelState["Saldo"].Errors.Any() ? "input-validation-error" : string.Empty )"
/>

Temos que realizar manualmente as duas tarefas que o helper faz por nós:

  • Estabelecer a propriedade value ao valor do ViewModel recebido se houver
  • Estabelecer a classe a input-validation-error no caso de haver um erro vinculado no campo que estamos mostrando.
Desse modo, os helpers não são imprescindíveis. Mas são muito cômodos e a maneira recomendável de construir formulários em ASP.NET MVC.

Vimos TextBoxFor e CheckBoxFor mas há um helper por cada controle HTML que habitualmente usamos em formulários, assim temos Html.TextAreaFor, Html.LabelFor, Html.DropDownListFor, etc?

Mostro o uso de Html.LabelFor porque é outro que se usa muitíssimo. Esse gera um campo

@Html.LabelFor(x=>x.Nome) @Html.TextBoxFor(x=>x.Nome) <br />

nos gera o código HTML:

<label for="Nome">Nome</label> <input id="Nome" name="Nome" type="text" value="" /> <br />

A etiqueta <label> se renderiza como texto plano. A vantagem de usá-la é que ao pressionar sobre a label o navegador dá o foco ao controle indicado no atributo for (nesse caso o textbox ao lado).

Personalização dos helpers

Se só posso passar a um helper uma expressão lambda que indica a propriedade para a qual deve renderizar um determinado controle HTML, como posso personalizá-los? Por personalizá-los me refiro a poder acrescentar atributos HTML adicionais como style ou qualquer outro.

Pois bem, muitos dos helpers têm uma sobrecarga onde admitem um objeto anônimo cujas propriedades serão mapeadas a atributos HTML ao gerar o código. Assim, o seguinte código na visão:

@Html.LabelFor(x => x.Nome) @Html.TextBoxFor(x => x.Nome, new { style = "border-color: blue", size = "30" })

Gera o seguinte código HTML:

<input id="Nome" name="Nome" size="30" style="border-color: blue" type="text" value="" />

Helpers "inteligentes"

Com os helpers que vimos até agora é nossa responsabilidade decidir que controle HTML mapeamos a cada propriedade (um textbox, uma checkbox, etc). Porém, ASP.NET MVC incorpora dois helpers, vamos chamá-los "inteligentes" que são capazes de determinar qual é o melhor controle para visualizar ou editar uma propriedade específica.

Esses dois helpers são:

  • HtmlDisplayFor: Renderiza o HTML necessário para visualizar uma propriedade (sem poder ser editada)
  • HtmlEditorFor: Renderiza o HTML necessário para poder editar uma propriedade.
Esses helpers são extraordinariamente potentes (tanto que vão ter um artigo só para eles) assim que por agora vamos ver apenas seu uso:

@using MvcHelpersForms.Models
@model Trabalhador
<form method="post">
@Html.LabelFor(x => x.Nome) @Html.EditorFor(x => x.Nome)
<br />
Sobrenome: @Html.EditorFor(x => x.Sobrenome)
<br />
Data Nascimento: @Html.EditorFor(x => x.DataNascimento)
<br />
Saldo: @Html.EditorFor(x => x.Saldo) <br />
É Fixo: @Html.EditorFor(x => x.EFixo)
<br />
<input type="submit" value="Enviar" />
</form>

Observem que agora usamos somente Html.EditorFor. O código HTML gerado agora é:

<form method="post">
<label for="Nome">Nome</label> <input class="text-box single-line" id="Nome" name="Nome" type="text" value="" />
<br />
Sobrenome: <input class="text-box single-line" id="Sobrenome" name="Sobrenome" type="text" value="" />
<br />
Data Nascimento: <input class="text-box single-line" id="DataNascimento" name="DataNascimento" type="text" value="" />
<br />
Saldo: <input class="text-box single-line" id="Saldo" name="Saldo" type="text" value="" /> <br />
É Fixo: <input class="check-box" id="EFixo" name="EFixo" type="checkbox" value="true" /><input name="EFixo" type="hidden" value="false" />
<br />
<input type="submit" value="Enviar" />
</form>

Este código é quase idêntico ao que tínhamos antes. Html.EditorFor renderiza uma caixa de texto para cada propriedade à exceção da booleana para a qual renderiza uma casa de verificação.

A pergunta evidente é: Se existe EditorFor para que usar o resto de helpers? Pois bem, quando vocês quiserem decidir que controle HTML se usa para visualizar ou mostrar uma propriedade vocês podem usar os helpers que vimos antes. Quando vocês quiserem que seja o sistema usem EditorFor (ou DisplayFor se vocês estiverem realizando uma visão que não permita editar). Como já adiantamos antes EditorFor e DisplayFor são extraordinariamente potentes e com eles se podem fazer autênticas maravilhas, mas isso vamos vê-lo em um próximo artigo.

O helper BeginForm

Bom, já que falamos de helpers para gerar formulários este é um bom momento para introduzir o helper BeginForm. O que este helper gera é? o tag <form>. Bem, na verdade o tag <form> e seu similar </form>. É por isso que esse helper se "usa" de uma forma um pouco? diferente:

@using (Html.BeginForm()) {
<!-- Código do formulário -->
}

O código que gera o formulário se incluiu dentro das chaves de abertura e fechamento. Quando se encontre a chave de fechamento se gerará o tag </form>. Ao usar BeginForm() devemos ter um pouco mais de cuidado com Razor. O código seguinte dá erro:

@Html.LabelFor(x => x.Nome) @Html.EditorFor(x => x.Nome)
<br />
Sobrenome: @Html.EditorFor(x => x.Sobrenome)
<br />
Data Nascimento: @Html.EditorFor(x => x.DataNascimento)
<br />
Saldo: @Html.EditorFor(x => x.Saldo) <br />
É Fixo: @Html.EditorFor(x => x.EFixo)
<br />
<input type="submit" value="Enviar" />
}

A razão é que Razor interpreta que deve executar o código que se encontra entre as chaves. É claro, como já vimos, Razor é o suficientemente inteligente para "ignorar" o código HTML (como <br />) mas não o texto plano. Ou seja, Razor tentará executar o código Sobrenome: (ou É Fixo:) que é um código totalmente inválido em C#, daí o erro.

A solução? A que vimos no artigo que dedicamos a Razor, ou então usamos @: ou usamos a etiqueta fictícia <text> para indicar a Razor que este texto plano é isso? texto plano, que deve mandar para a saída HTML , só isso:

@using (Html.BeginForm()) {
@Html.LabelFor(x => x.Nome) @Html.EditorFor(x => x.Nome)
<br />
@:Sobrenome: @Html.EditorFor(x => x.Sobrenome)
<br />
@:Data Nascimento: @Html.EditorFor(x => x.DataNascimento)
<br />
<text>Saldo:</text> @Html.EditorFor(x => x.Saldo) <br />
<text>É Fixo:</text> @Html.EditorFor(x => x.EFixo)
<br />
<input type="submit" value="Enviar" />
}

Bom! Suficiente por hoje, não? Neste artigo vimos o que são os helpers para formulário, como se usam e quais são suas vantagens. No artigo seguinte vamos falar de um assunto importantíssimo: as validações






Usuários :    login / registro

Manuais relacionados
Categorias relacionadas
O autor

Home | Sobre nós | Copyright | Anuncie | Entrar em contato