ASP .NET MVC - Filtrando registros com Dropdownlist
Se você pretende desenvolver páginas web dinâmicas usando a tecnologia ASP .NET MVC provavelmente vai se deparar com a tarefa de ter que exibir uma lista de itens selecionáveis em uma página e de realizar operações para filtrar registros conforme uma condição.
Uma lista de itens selecionáveis é obtida usando o controle DropDownList que na verdade é renderizado como um elemento Select da HTML que usa a tag <select></select>.
É uma tarefa simples mas se você procurar na web sobre o assunto pode ficar um pouco confuso com as informações obtidas se estiver começando agora com a tecnologia ASP .NET MVC ou se você for usuário dos Web Forms da ASP .NET.
Uma das causas da confusão é que esta tarefa pode ser feito de diversas formas e isso pode variar dependendo do tipo de projeto (Usando JQuery, Json, etc.), do tipo engine usado no projeto ( .ASPX ou Razor), da origem dos itens (arquivo XML, arquivo Texto, Banco de dados, lista de itens, etc.) e qual a linguagem usada (C# ou VB .NET)
Este artigo procura ser bem direto e objetivo mostrando apenas o que é necessário para filtrar registros usando o controle DropDownList na tecnologia ASP .NET MVC.
Ferramentas utilizadas
Filtrando registros com ASP .NET MVC
Abra o VS 2012 Express for Web, clique em New Project e selecione o template Visual C# -> Web -> ASP .NET MVC 4 Web Application;
Informe o nome Mvc_FiltrarRegistros e escolha o local onde você deseja salvar o projeto (Location) informando também o nome da solução e clique em OK;
A seguir selecione o template Basic e o engine Razor; com isso será criado um projeto com uma estrutura MVC básica (ver figura abaixo) que iremos usar a alterar conforme nossas pretensões;
Será criado o projeto completo com a estrutura das pastas padrão de um projeto ASP .NET MVC.
Podemos observar no projeto asa seguintes pastas :
Não precisa ser muito esperto para perceber que estes diretórios contém os arquivos que irão implementar o MVC - Model , View e o Controller. (Modelo, Visão e Controlador)
Definindo o Model
Vamos iniciar definindo o nosso Model que será representando pelas entidades geradas pelo Entity Framework com o banco de dados Northwind.mdf.
Vamos criar um Entity data Model clicando com o botão direito sobre a pasta Models e selecionando Add New Item;
A seguir selecione o template Data-> ADO .NET Entity Data Model e informe o nome Northwin.edmx e clique em Add;
Na janela Choose Model Contents selecione : Generate from database e clique em Next>;
Selecione a conexão com o banco de dados Northwind(Se ela não existir clique em New Connection e crie a conexão), e informe o nome NorthwindEntities deixando a opção Save Entity connection settings in Web.Config marcada e clique em Next>;
Selecione todas as tabelas ; marque as caixas de seleção, aceite o nome para o namespace Model e clique em Finish;
O arquivo Northwind.edmx será gerado e poderá ser visualizado exibindo o modelo de entidades relacionadas que foi obtido a partir das tabelas do banco de dados Northwind.mdf;
Selecionando o modelo podemos ver na janela Properties (pressione F4) que o nome do nosso container é NorthwindEntities;
Usando o Model
Nosso próximo passo seria criar um controlador clicando com o botão direito do mouse sobre a pasta Controllers, selecionar a opção Add Controller e definindo as configurações conforme a figura abaixo:
Ao clicar no botão Add seria criado o controlador CustomersController.cs na pasta Controllers e todas as Views na pasta Views->Customers conforme mostra a figura abaixo:
Se você executar a aplicação neste momento vai encontrar um erro do tipo: Não é possível encontrar o recurso.
Precisamos alterar a rota que foi definida para o Controller no arquivo RouteConfig da pasta App_Start .
O valor padrão esta assim : controller="Home" e temos que alterar para controller="Customers" conforme mostrado abaixo:
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; using System.Web.Routing; namespace Mvc_FiltrarRegistros { public class RouteConfig { public static void RegisterRoutes(RouteCollection routes) { routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); routes.MapRoute( name: "Default", url: "{controller}/{action}/{id}", defaults: new { controller = "Customers", action = "Index", id = UrlParameter.Optional } ); } } } |
Após isso vamos ajustar a view Index.cshtml que foi gerada na pasta Views/Customers alterando o seu código para que ela exiba apenas algumas informações dos clientes e não todas como padrão. Abaixo temos o código alterado da view Index.cshtml:
@model IEnumerable<Mvc_FiltrarRegistros.Models.Customer> @{ ViewBag.Title = "Index"; } <h2>Clientes </h2> <table> <tr> <th> @Html.DisplayNameFor(model => model.CompanyName) </th> <th>@Html.DisplayNameFor(model => model.ContactName) </th> <th>@Html.DisplayNameFor(model => model.City) </th> <th> @Html.DisplayNameFor(model => model.Country)</th> <th> @Html.DisplayNameFor(model => model.Phone) </th> <th></th> </tr> @foreach (var item in Model) { <tr> <td>@Html.DisplayFor(modelItem => item.CompanyName) </td> <td> @Html.DisplayFor(modelItem => item.ContactName) </td> <td> @Html.DisplayFor(modelItem => item.City) </td> <td> @Html.DisplayFor(modelItem => item.Country) </td> <td> @Html.DisplayFor(modelItem => item.Phone) </td> <td> @Html.ActionLink("Edit", "Edit", new { id=item.CustomerID }) | @Html.ActionLink("Details", "Details", new { id=item.CustomerID }) | @Html.ActionLink("Delete", "Delete", new { id=item.CustomerID }) </td> </tr> } |
Agora executando o projeto teremos o resultado abaixo:
As informações são obtidas pela Action Index do controlador e repassada à respectiva view Index.cshtml. O código atual da Action Index do nosso controlador CustomerController é :
using System.Data; using System.Linq; using System.Web.Mvc; using Mvc_FiltrarRegistros.Models; namespace Mvc_FiltrarRegistros.Controllers { public class CustomersController : Controller { private NorthwindEntities db = new NorthwindEntities(); // // GET: /Customers/ public ActionResult Index() { return View(db.Customers.ToList()); }
..... } |
Vamos alterar o código da Action Index() conforme abaixo :
public ActionResult Index() { var model = from c in db.Customers orderby c.ContactName select c; return View(model); } |
Se executarmos novamente a aplicação a única diferença e que teremos uma relação de clientes ordenados pelo campo ContactName.
Vamos então permitir que o cliente filtre os registros por pais(country) alterando a nossa Action e incluindo uma string de consulta usando a cláusula Where para filtrar pelo campo Country. Veja como ficou a Action Index() do controlador:
// // GET: /Customers/ public ActionResult Index(string pais) { var model = from c in db.Customers orderby c.ContactName where c.Country == pais select c; return View(model); } |
Executando o projeto novamente após essa alteração teremos o seguinte resultado:
Esse resultado era previsto pois a action Index realiza a consulta com base em uma query string que deverá ser informada contendo o nome do país para poder realizar o filtro. Como na primeira execução chamamos diretamente a action Index sem passar parâmetro algum o resultado não retornar nenhuma informação.
Vamos então passar via URL a query string informando o país igual a Brazil, fazendo isso iremos obter:
Note que informamos na URL a string de consulta na forma: customers?pais=Brazil
Alterando a consulta na action Index conforme abaixo, se nada for informado na URL agora serão retornados todos os registros:
// // GET: /Customers/ public ActionResult Index(string pais) { var model = from c in db.Customers orderby c.ContactName where c.Country == pais || pais.Equals(null) || pais.Equals("") select c; return View(model); } |
E se quisermos filtrar por pais e por cidade (campos Country e City) ?
Para isso basta alterar a consulta conforme a abaixo incluindo mais uma cláusula Where que filtra pelo campo City:
// // GET: /Customers/ public ActionResult Index(string pais, string cidade) { var model = from c in db.Customers orderby c.ContactName where c.Country == pais || pais.Equals(null) || pais.Equals("") where c.City == cidade || cidade.Equals(null) || cidade.Equals("") select c; return View(model); } |
Agora informando o pais e a cidade na URL iremos obter para pais=Brazil e cidade=Rio de Janeiro o seguinte resultado:
A string de consulta usada na URL foi : customers?pais=Brazil&cidade=Rio de Janeiro
Regras padrão para mapeamento das
URLs Um método Action possui um mapeamento um-para-um com uma interação do usuário como : clicar um link, informar um url no navegador e submeter um formulário; Cada uma dessas interações do usuário resulta em uma requisição que é enviada ao servidor, sendo que em cada caso a URL da requisição inclui informação que o framework MVC usa para invocar um método Action; Assim, quando um usuário informa uma URL no navegador , a aplicação MVC usa as regras de roteamento que são definidas no arquivo Global.asax para realizar o parse da URL e determinar o caminho do controller e o controller então determina o método Action apropriado para tratar a requisição. Por padrão a URL de uma requisição é tratada como um sub-caminho que inclui o nome do controller seguido pelo nome da Action(ação). Exemplo: - Se um usuário informar a URL : http://macoratti.com/Vendas/Produtos/Categorias o sub-caminho é /Produtos/Categorias; - As regras de roteamento tratam "Produtos" como o nome do controller e "Categorias" como o nome da Action; - Desta forma a regra de roteamento invoca o método Categorias do controller Produtos a fim de processar a requisição; - Se a URL terminar com /Produtos/Detalhes/5 o roteamento padrão trata "Detalhes" como sendo o nome da Action e o método Detalhes do controller Produtos será invocado para processar a requisição; - O valor 5 na URL será passado para o método "Detalhes" como um parâmetro; |
Com base nisso vamos tomar mais amigável a nossa interface e realizar o filtro por pais e cidade usando controles dropdownlist.
Filtrando com DropDownList
Para fazer isso vamos modificar a nossa Action Index no controlador e utilizar a propriedade ViewBag que é usada para persistir dados entre o Controlador e a View.
Nota: Lembrem-se que segundo o padrão MVC, o controlador é o responsável por acessar o modelo e obter os dados para enviá-los para a view. A view deve apenas exibir os dados (ou solicitar novos dados). Os dados que o modelo fornece controlador podem vir de qualquer fonte de dados( banco de dados, xml, arquivo texto, etc.)
A propriedade ViewBag é um dicionário chave/valor que usa os recursos dos tipos dinâmicos da linguagem C# sendo um objeto dinâmico onde podemos adicionar propriedades (no controller) e ler essas propriedades posteriormente(na view). Podemos definir propriedades da seguinte forma ViewBag.chave=valor.
ViewBag.Nome = "Jose Carlos
Macoratti";
ViewBag.Data = new DateTime(2013, 10, 10);
Lembrando que o tempo de vida da ViewBag dura apenas entre o envio através do controller e a exibição na View após isso ela fica nula novamente, então se houver um redirect a viewbag se tornará nula.
Nota: A propriedade ViewData também pode ser usada para os mesmos propósitos sendo um dicionário de objetos . Ex: ViewData["Nome"] = "Macoratti"; (O ViewBag esta disponível a partir da ASP .NET MVC 3; já o ViewData existe desde a primeira versão.)
// // GET: /Customers/ public ActionResult Index(string pais,string cidade) { ViewBag.Country = (from c in db.Customers select c.Country).Distinct(); ViewBag.City = (from c in db.Customers select c.City).Distinct(); var model = from c in db.Customers orderby c.ContactName where c.Country == pais || pais.Equals(null) || pais.Equals("") where c.City == cidade || cidade.Equals(null) || cidade.Equals("") select c; return View(model); } |
Agora basta alterar o código da view Index.cshtml criando os controles dropdownlist conforme abaixo:
@model IEnumerable<Mvc_FiltrarRegistros.Models.Customer> @{ ViewBag.Title = "Index"; } <h2>Clientes </h2> <p> @using (Html.BeginForm()) { <text>Pais</text>@Html.DropDownList("pais", new SelectList(ViewBag.Country)) <text>Cidade</text>@Html.DropDownList("cidade", new SelectList(ViewBag.City)) <input type="submit" value="Procurar" /> } </p> ... ... |
O método Html.BeginForm é um HTML Helper que gera um elemento de formulário HTML configurado para um postback para o método action. Uma vez que não se passaram os parâmetros para o método auxiliar, ele assume que queremos dar um postback para a mesma URL. Um truque é usar isso em uma declaração using :
@using (Html.BeginForm()) {
...conteúdo do formulario...
}
Normalmente a instrução using garante que um objeto é descartado quando sai do escopo. Ele é usado para conexões de bancos de dados, por exemplo, para se certificar de que elas serão fechadas assim que uma consulta for concluída.
Em vez de descartar um objeto, o Helper Html.BeginForm fecha o elemento de formulário HTML quando sai do escopo. Isto significa que o método Html.BeginForm cria ambas as partes de um elemento de formulário :
<form action="/Home/RsvpForm" method="post">
...conteudo do formulario...
</form>
Executando o projeto novamente agora teremos:
@model IEnumerable<Mvc_FiltrarRegistros.Models.Customer> @{ ViewBag.Title = "Index"; } <h2>Clientes </h2> <p>
@using (Html.BeginForm(("Index","Customers",FormMethod.Get))
{
<text>Pais</text>@Html.DropDownList("pais", new SelectList(ViewBag.Country))
<text>Cidade</text>@Html.DropDownList("cidade", new SelectList(ViewBag.City))
<input type="submit" value="Procurar" />
}
</p>
...
...
|
Executando o projeto novamente agora teremos:
Observe que a string de consulta agora esta visível na URL devido ao método GET.
Quando um usuário informa os dados nos campos de um formulário e o submete, os dados contidos em cada campo do formulário são transferidos para o servidor. Se o formulário estiver usando o método GET, os dados são anexados à URL como uma string de argumento. Quando o formulário utilizar o método POST os dados são enviados no corpo da solicitação HTTP e não são adicionados á URL tornando mais fácil o processamento da solicitação e melhorando o desempenho do servidor. |
Pegue o projeto completo aqui: Mvc_FiltrarRegistros.zip (sem as referências)
Rom 12:20
Antes, se o teu inimigo tiver fome, dá-lhe de comer; se tiver sede, dá-lhe de beber; porque, fazendo isto amontoarás brasas de fogo sobre a sua cabeça.Rom 12:21
Não te deixes vencer do mal, mas vence o mal com o bem.Gostou ? Compartilhe no Facebook Compartilhe no Twitter
Referências:
Super DVD Vídeo Aulas - Vídeo Aula sobre VB .NET, ASP .NET e C#
http://msdn.microsoft.com/pt-br/library/system.web.mvc.html.formextensions.beginform%28v=vs.100%29.aspx - Html.BeginForm
http://msdn.microsoft.com/pt-br/library/dd410596%28v=vs.100%29.aspx - HTML Helpers
ASP .NET MVC 3 - Apresentando os recursos básicos para iniciantes - II