Asp.Net MVC - Enviando dados para o servidor com KnockoutJS e JQuery    

Olá pessoal.

Já faz um tempo que falei de KnockoutJS. Hoje vou falar mais uma vez para tirar uma dúvida recorrente aqui no blog: Como enviar dados do meu modelo KnockoutJS para uma Action do MVC.

Vou fazer um exemplo simples e objetivo. Como o título do post diz, a ideia é mostrar apenas o envio dos dados para o servidor, como obter do servidor não será abordado (quem sabe em outro post).

Vamos explicar como será a aplicação na imagem abaixo:

Imagem 1 – Tela de cadastro.

Imagem 1 – Tela de cadastro.

A tela é divida em três partes:

  1. Na primeira parte é exibido um formulário onde você pode digitar dados de contato e clicar em adicionar
  2. Na segunda parte são exibidos os contatos já adicionados. Você pode clicar no link Remover no final de cada linha para remover o item já adicionado.
  3. Na terceira parte você pode clicar no botão Salvar. Apenas após clicar nesse botão seus dados adicionados a lista serão enviados para o servidor.

A aplicação é bem simples, mas é o suficiente para mostra como enviar dados do JavaScript para o servidor.

Vamos agora ver como a tela foi feita.

   1:  <h3>Cadastro:</h3>
   2:   
   3:  <label for="nome">Nome</label>
   4:  <input id="nome" name="nome" type="text" data-bind="value:Nome" /><br />
   5:  <label for="telefone">Telefone</label>
   6:  <input id="telefone" name="telefone" type="text" data-bind="value:Telefone" /><br />
   7:  <label for="email">E-mail</label>
   8:  <input id="email" type="email" name="email" data-bind="value:Email" /><br />
   9:  <input type="button" data-bind="click:adicionarContato" value="Adicionar >>" />
  10:   
  11:  <table>
  12:      <thead>
  13:          <th>Nome</th>
  14:          <th>Telefone</th>
  15:          <th>E-mail</th>
  16:          <th></th>
  17:      </thead>
  18:      <tbody data-bind="foreach: Contatos">
  19:          <tr>


  21:              <td><input type="text" data-bind="value:Telefone" /></td>
  22:              <td><input type="text" data-bind="value:Email" /></td>
  23:              <td><a href='#' data-bind='click: MeuModelo.removerContato'>Remover</a></td>
  24:          </tr>
  25:      </tbody>
  26:  </table>
  27:  <input type="button" value="Salvar" data-bind="click:salvarContato" />

Esse é todo o HTML utilizado para fazer a tela acima. Da 1 à 9 crio o formulário para adicionar contatos. Da linha 11 à 26 crio a tabela que é exibido os registros adicionados, e por fim na linha 27 adiciono o botão para salvar no servidor.

Repare que em todos os campos estou adicionando o atributo data-bind do KnockoutJS. Para os botões informo que vou utilizar o evento click para invocar o respectivo método do meu modelo (abaixo). Para os campos (input) informo no data-bind que desejo que o atributo value seja preenchido  com o respectivo valor.

Para utilizar o KnockoutJS, posso fazer o download direto no site http://knockoutjs.com ou apenas utilizar o Nuget. No meu caso vou utilizar o Nuget com o comando abaixo no Visual Studio:

PM> Install-Package knockoutjs

Uma vez executado, todos os arquivos necessários para utilizar o Knockout estarão na pasta de Scripts do meu site:

Imagem 2 – Scripts do Site

Imagem 2 – Scripts do Site.

Também vou adicionar a referência para o Jquery e para a biblioteca do KnockoutJS que acabamos de instalar:

<script type="text/javascript" src="@Url.Content("~/Scripts/jquery-1.7.1.min.js")"></script>
<script type="text/javascript" src="@Url.Content("~/Scripts/knockout-2.2.1.js")"></script>

Agora vamos ao JavaScript necessário para fazer minha aplicação funcionar:

   1:  <script type="text/javascript">
   2:  var MeuModelo = {
   3:      Nome: ko.observable(),
   4:      Telefone: ko.observable(),
   5:      Email: ko.observable(),
   6:      Contatos: ko.observableArray([]),
   7:      adicionarContato: function () {
   8:          this.Contatos.push({ Nome: this.Nome(), Telefone: this.Telefone(), Email: this.Email() })
   9:          this.Nome("");
  10:          this.Telefone("");
  11:          this.Email("");
  12:      }
  13:      , removerContato: function (contato) {
  14:          MeuModelo.Contatos.remove(contato);
  15:      }
  16:      , salvarContato: function () {
  17:          var dados = ko.toJS(MeuModelo.Contatos);
  18:          $.ajax({
  19:              type: "POST",
  20:              contentType: "application/json",
  21:              url: "Home/SalvarContato",
  22:              data: JSON.stringify({ contatos: dados }),
  23:              traditional: true,
  24:              success: MeuModelo.sucesso,
  25:              error: MeuModelo.falha
  26:          });
  27:      }
  28:      ,sucesso: function () { alert("Sucesso");}
  29:      ,falha: function () { alert("Falha"); }
  30:   
  31:      };
  32:   
  33:  ko.applyBindings(MeuModelo);
  34:  </script>

No JavaScript acima estou criando um ViewModel, ou seja, um modelo para gerenciar minha View. Vamos explicar linha por linha:

  • Da linha 3 a 5 estou criando as propriedades observáveis para os três campos do formulário que adiciona os contatos.
  • Na linha 6 estou criando o Array observável que conterá os registros da lista da tela.
  • Entre as linhas 7 e 12 crio o método que será chamado quando for clicado no botão Adicionar. Esse método adiciona os valores atuais das propriedades criadas entre as linhas 3 e 5 ao Array Contatos. Uma vez que o Array muda no JavaScript, a tela atualiza automaticamente. Esse é o KnockoutJS em ação. Para finalizar o método, entre as linhas 9 e 11 eu limpo os campos onde os valores foram digitados.
  • Entre as linhas 13 e 15 eu implemento o método responsável por remover um item do array e atualizar a tela quando clicado no link Remover na lista.
  • Entre as linhas 16 e 29 eu crio o método responsável por enviar os dados ao Servidor. Primeiramente, na linha 17 eu transforme o meu Array observável em um Array puro de JavaScript utilizando o método do KnockoutJS chamado ko.toJS. Em seguida invoco o método ajax do JQuery, invocando o método POST e definido que o conteúdo será do tipo “application/json”. Para enviar os dados ao servidor, eu transformo meus dados em uma string JSON, encapsulando o Array em um campo com o mesmo nome do parâmetro da Action. (Linha 22)
  • Por fim, na linha 33 eu aplico o Binding entre o meu modelo JavaScript e a minha página HTML.

Agora, por último, devemos ver como criar a Action em meu Controller MVC.

É bem simples. Primeiro crio um ViewModel de Contato em meu C#, e em seguida crio uma Action que recebe um um array desse ViewModel:

   1:  namespace Mvc_Knockout.Models
   2:  {
   3:      public class Contato
   4:      {
   5:          public string Nome { get; set; }
   6:          public string Telefone { get; set; }
   7:          public string Email { get; set; }
   8:      }
   9:  }

E a Action:

   1:  [AcceptVerbs(HttpVerbs.Post)]
   2:  public JsonResult SalvarContato(Contato[] contatos)
   3:  {
   4:      foreach (var contato in contatos)
   5:      {
   6:          //Lógica para salvar
   7:      }
   8:      return Json(contatos);
   9:  }

Informo que minha Action receberá um Post, e não um simples Get, pois informei na chamada Ajax que enviaria um Post. Uma vez que os dados estiverem no servidor, você pode utilizar a lógica e ferramenta que achar melhor para persistir, como NHibernate ou Entity Framework.

Veja abaixo o print dos meus dados no servidor após clicar no botão Salvar. (Os mesmos dados que estão na tela da imagem da tela (Imagem 1))

 

Imagem 3 – Dados no Servidor.

Imagem 3 – Dados no Servidor.

É isso pessoal. Por hoje era isso.

Até o próximo.

Fonte do Projeto:

Mvc+Knockout.zip (3,01 mb)

18. fevereiro 2013 23:57 by Frederico B. Emídio | Comments (1) | Permalink

Utilizando JQGrid com WebForms    

Olá pessoal!

Muitas pessoas têm dificuldades de utilizar plugins JQuery com WebForms. Principalmente porque desenvolvedor WebForm muitas vezes sabe usar apenas ServerControls, desconhecendo muitos conceitos básicos de Web em sí. Não é a toa que fiz uma série de post nesse blog mostrando conceitos de Web com WebForms.

Geralmente, quando uma pessoa vê exemplos de JQuery, eles estão em PHP, e a pessoa acredita que não funcionaria com WebForms, ou mesmo que saiba que seja possível, não sabe como adaptar para WebForm. Obs.: Geralmente esse problema não acontece com quem desenvolve com Asp.Net MVC.

Nos últimos post, mostrei alguns conceitos que podem ajudar, todos relacionados a PageMethods, como esse e esse. Se você não leu nenhum deles, ou está caindo diretamente nesse post, aconselho fortemente a ler pelo menos esse: Invocando PageMethods diretamente com JQuery.

Se você entender bem esse post que citei, nem precisará desse para utilizar o JQGrid ou qualquer outro plugin JQuery.

Então vamos lá!

Nesse post, vou utilizar as funcionalidades básicas do JQGrid, como Listar, Pesquisar e Editar/Adicionar.

O mais básico, e que todo mundo utiliza, é o Listar. Vou fazer o seguinte no meu HTML/JavaScript:

   1: <script type="text/javascript">
   2:     $().ready(function () {
   3:          $.ajaxSetup({
   4:                dataFilter: function (data, type) {
   5:                    if (type == "json" || type == undefined) {
   6:                        var msg = eval('(' + data + ')');
   7:                        if (msg.hasOwnProperty('d'))
   8:                            return JSON.stringify(msg.d);
   9:                        else
  10:                           return data;
  11:                   }
  12:                   else return data;
  13:               }
  14:            });
  15:  
  16:         $("#tbGrid").jqGrid({
  17:             mtype: "post",
  18:             url: '/Default.aspx/Listar',
  19:             datatype: "json",
  20:             ajaxGridOptions: { contentType: 'application/json; charset=utf-8' },
  21:             colNames: ['ID', 'Nome', 'Idade', 'E-mail'],
  22:             colModel: [
  23:                        { name: 'PessoaID', index: 'PessoaID', width: 55 },
  24:                        { name: 'Nome', index: 'Nome', width: 150 },
  25:                        { name: 'Idade', index: 'Idade', width: 100 },
  26:                        { name: 'Email', index: 'Email', width: 150 }
  27:                    ],
  28:             rowNum: 10,
  29:             rowList: [10, 20, 30],
  30:             pager: '#pager',
  31:             sortname: 'PessoaID',
  32:             viewrecords: true,
  33:             sortorder: "desc",
  34:             caption: "JQGrid com WebForms",
  35:             serializeGridData: function (dados) {
  36:                 return JSON.stringify(dados)
  37:             },
  38:             jsonReader: { repeatitems: false, id: "PessoaID" }
  39:  
  40:         });
  41:         $("#tbGrid").jqGrid('navGrid', '#pager', { edit: false, add: false, del: false });
  42:     });
  43: </script>
  44: <table id="tbGrid">
  45: </table>
  46: <div id="pager">
  47: </div>

Até ai não fiz nada de mais, adicionei configurações padrões na Grid. Adicionei quatro colunas que virão do meu PageMethod, que está na página Default.aspx com o nome Listar.

Como será que deve ficar meu PageMethod para aceitar a requisição dessa Grid? Se não sabe, ai vai uma dica: Utilizando o Fiddler ou o DevelopToolBar, você pode ver qual HTTP Request o Grid está fazendo. Verificando quais campos estão lá você saberá que são os mesmos parâmetros que deve ter no seu PageMethod.

No meu caso, o JQGrid mandou os seguintes campos:

{"_search":false,"nd":1314831637255,"rows":10,"page":1,"sidx":"PessoaID","sord":"desc"}

No meu caso, o que importa é :

  • rows – Representa a quantidade de linha por página.
  • page – Indica a página atual.
  • sidx – Indica o campo pelo qual a Grid está ordenada. Sidx significa Search Index
  • sord – Indica a ordem que o campo definido em sidx deve ser ordenado.

Nesse caso, se meu PageMethod tiver esses campos já será o suficiente. Abaixo segue a implementação dele:

   1: [WebMethod]
   2: public static Reader<Pessoa> Listar( string sidx, string sord, int page, int rows)
   3: {
   4:     var modelo = new Modelo();
   5:     var lista = modelo.Pessoas.ToList();
   6:     var reader = new Reader<Pessoa>(lista,page,rows);
   7:     return reader;
   8: }

Como ele faz a busca, muda de solução para solução. No meu caso eu estou realizando a pesquisa em um SQLServer CE com EntityFramework. Minha classe Reader é responsável por realizar uma “paginação” nos registros retornados e retornar os campos de acordo com o JSONReader da JQGrid. Todo o código fonte dele está abaixo, apenas por curiosidade, visto que você não precisa dele para fazer seu JQGrid funcionar, ele apenas ajuda:

   1: public class Reader<T>
   2: {
   3:    /// <summary>
   4:    /// Número de páginas retornadas no registro
   5:    /// </summary>
   6:    public int total { get; set; }
   7:    /// <summary>
   8:    /// Página atual que a Grid exibirá
   9:    /// </summary>
  10:    public int page { get; set; }
  11:    /// <summary>
  12:    /// Número total de registros na base.
  13:    /// </summary>
  14:    public int records { get; set; }
  15:    /// <summary>
  16:    /// Lista com cada registro.
  17:    /// </summary>
  18:    public List<T> rows { get; set; }
  19:  
  20:    /// <summary>
  21:    /// Construtor recebe a lista e faz a paginação virtual.
  22:    /// </summary>
  23:    /// <param name="lista">Lista com os registros</param>
  24:    /// <param name="paginaAtual">Página atual.</param>
  25:    /// <param name="totalPorPagina">Total de registros por páginas</param>
  26:    public Reader(List<T> lista,int paginaAtual, int totalPorPagina)
  27:    {
  28:  
  29:        var totalRegistros = lista.Count();
  30:        page = paginaAtual;
  31:        var ini = (page - 1) * totalPorPagina;
  32:        var fim = totalRegistros > totalPorPagina ? totalPorPagina : totalRegistros;
  33:        
  34:        if (ini > 0)
  35:        {
  36:            fim = totalPorPagina;
  37:            fim = fim - 10 >= 0 ? totalRegistros % totalPorPagina : fim;
  38:        }
  39:        var totalPags = totalRegistros / totalPorPagina;
  40:        if (totalRegistros % totalPorPagina > 0)
  41:        {
  42:            totalPags++;
  43:        }
  44:        total = totalPags;
  45:        page = page;
  46:        records = totalRegistros;
  47:        rows = lista.ToList().GetRange(ini, fim);
  48:    }
  49: }

Com os códigos acima minha Grid já está funcionando:

image

Se, por exemplo, eu mudo a quantidade de registros por página, a Grid vai passar os novos valores nos parâmetros do PageMethod, e minha pesquisa retornará a nova quantidade de registros por página:

{"_search":false,"nd":1314832264231,"rows":"20","page":1,"sidx":"PessoaID","sord":"desc"}

E se eu quiser utilizar os campos de pesquisa do JQGrid? Será que o PageMethod já está preparado? Vamos ver. Vou buscar pelo usuário de nome “Frederico” na lista da Grid, vamos ver o que a JQGrid envia para o servidor utilizar o Fiddler ou o IEDeveloperToolbar, ou qualquer ferramenta de sua vontade. Utilizando a “Lupa” da Grid e selecionando o campo na popup que aparece:

image

O que ele envia é o seguinte:

{"_search":true,"nd":1314832456208,"rows":"20","page":1,"sidx":"PessoaID","sord":"desc", "searchField":"Nome","searchString":"Frederico","searchOper":"eq","filters":""}

Veja que alguns campos foram adicionados e outros estão com novos valores, os campos que teremos que adicionar em nosso PageMethod são:

  • _seach – Indica se está sendo realizando uma pesquisa ou se é apenas a listagem do dados
  • searchField – Indica por qual campo está sendo pesquisado.
  • searchString – Indica qual é o valor pesquisado.
  • searchOper – Indica qual é o operado utilizado para a pesquisa.

Vou alterar meu PageMethod  para ficar da seguinte forma:

   1: [WebMethod]
   2: public static Reader<Pessoa> Listar(GridParams param)
   3: {
   4:     var modelo = new Modelo();
   5:     List<Pessoa> lista;
   6:  
   7:     if (param._search)
   8:     {
   9:         var operador = new Func<string,string,string>((op,valor) =>
  10:         {
  11:              int saida;
  12:              bool isNum = Int32.TryParse(valor, out saida);
  13:             switch(op){
  14:                 case "ne":
  15:                     return isNum? string.Format(" <>{0}", valor): string.Format(" <>\"{0}\"", valor);
  16:                 default:
  17:                     return isNum ? string.Format(" = {0}", valor) : string.Format(" = \"{0}\"", valor);
  18:                 }
  19:         });
  20:  
  21:         var sb = new StringBuilder();
  22:         sb.Append(param.searchField);
  23:         sb.Append(operador(param.searchOper,param.searchString));
  24:         lista = modelo.Pessoas.Where(sb.ToString()).ToList();
  25:     }
  26:     else{
  27:         lista = modelo.Pessoas.ToList();
  28:     }
  29:     
  30:     var reader = new Reader<Pessoa>(lista, param.page, param.rows);
  31:     return reader;
  32: }

Primeira mudança importante é que troquei todos os parâmetros por uma classe. A classe encapsula todos aqueles campos que a JQGrid envia para o servidor, independente do Request. Apesar de ser bem simples, segue o código:

   1: public class GridParams
   2: {
   3:     public string sidx;
   4:     public string sord;
   5:     public int page;
   6:     public int rows;
   7:     public bool _search;
   8:     public string searchField;
   9:     public string searchString;
  10:     public string searchOper;
  11: }

Criei essa classe para receber todos os parâmetros porque o Asp.Net não aceita WebServices/PageMethods com parâmetros opcionais ou com Overloads, então criei um método com apenas um parâmetro, que pode ter todos os campos definidos ou não. Visto que a JQGrid utiliza o mesmo método para listar e pesquisar, essa é a única solução.

O resto é apenas a lógica do método, que você pode mudar com a sua no lugar, a minha é só para exemplo. O segredo está em validar o parâmetro _search, se ele for true quer dizer que o usuário está realizando uma pesquisa, e não apenas carregando a lista. Para simular, criei apenas lógica necessária para o usuário usar um Campo como critério igual ou diferente do valor que for fornecido.

Com isso minha lógica já estará funcionando.

Como mudei o parâmetro do PageMethod, preciso apenas alterar um evento na configuração da Grid, para encapsular o nome do parâmetro:

   1: serializeGridData: function (dados) {
   2:    return JSON.stringify({param: dados})
   3: },

Esse evento é invocado pela Grid logo antes da requisição ser enviada para o servidor, então eu coloco os parâmetros dentro do campo param. E pronto! sua Grid está funcionando perfeitamente com Asp.Net WebForm.

Para finalizar, vamos fazer a Grid conseguir criar e alterar registros

Adicionando  e Alterando registro com JQGrid

Antes de mais nada, devo habilitar algumas configurações no Pager da grid, fazendo que o botão de adicionar e editar apareça:

   1: $("#tbGrid").jqGrid('navGrid', '#pager', { edit: true, add: true, del: false });

E alterar o ColModel para dizer como será a edição de cada campo:

   1: colModel: [
   2:    { name: 'PessoaID', index: 'PessoaID', width: 55, editable: false, editoptions: { readonly: true, size: 10} },
   3:    { name: 'Nome', index: 'Nome', width: 150, editable: true, editoptions: { size: 50} },
   4:    { name: 'Idade', index: 'Idade', width: 100, editable: true, editoptions: { size: 2 }, editrules: {integer:true} },
   5:    { name: 'Email', index: 'Email', width: 150, editable: true, editoptions: { size: 50 }, editrules: { email: true} }
   6: ],

Depois adicionar a opção para definir o caminho do PageMethod responsável por salvar o registro:

   1: editurl: "/Default.aspx/Salvar"

Também devemos alterar algumas configurações da Grid para conseguir tratar o JSON, porque infelizmente o JQuery tem um problema ao converter os dados para JSON automaticamente, então nós mesmos temos que fazer isso. Para isso, vamos alterar algumas informações padrões da Grid:

   1: $.extend($.jgrid.edit,
   2: {
   3:     ajaxEditOptions: { contentType: "application/json;charset=utf-8" },
   4:     serializeEditData: function (data) {
   5:         return JSON.stringify(data);
   6:     }
   7: });

Feito isso, não precisamos mais fazer nada no JavaScript, apenas preparar o PageMethod. que você verá que é autoexplicativo:

   1: [WebMethod]
   2: public static void Salvar(string Nome, int Idade, string Email, string oper, string id)
   3: {
   4:     var modelo = new Modelo();
   5:     if (oper == "add")
   6:     {
   7:         var pessoa = new Pessoa
   8:         {
   9:             Nome = Nome,
  10:             Idade = Idade,
  11:             Email = Email
  12:         };
  13:         modelo.Pessoas.Add(pessoa);
  14:     }
  15:     else
  16:     {
  17:         var pessoa = modelo.Pessoas.Where("PessoaID = " + id).ToList()[0];
  18:         pessoa.Nome = Nome;
  19:         pessoa.Idade = Idade;
  20:         pessoa.Email = Email;
  21:     }
  22:     modelo.SaveChanges();
  23: }

E pronto!

Com isso você já pode testar a alteração e inclusão clicando nos botões que aparecem na barra da Grid:

Alterando registro com JQGrid X WebForms

Criando registro com JQGrid X WebForms

É isso pessoal, com o que foi passado nesse post você já consegue ir muito além. Você viu que tudo é possível com a estrutura que o Asp.Net fornece para o WebForm.

Espero que isso ajude. Muitas pessoas já me perguntaram sobre JQGrid com WebForm, isso deve ajudar muita gente.

Abraços e até o próximo!

 

::Atualização

Estou publicando o exemplo do código para esclarecer as dúvidas de alguns. Qualquer problema, comente ai embaixo.

Abs.

JQGridWebForm.zip (3,04 mb)

2. setembro 2011 00:39 by Frederico B. Emídio | Comments (15) | Permalink

Resolvendo o problema do “d” na serialização JavaScript (JSON) do Asp.Net    

Olá pessoal!

Hoje vou falar de um problema que muitos desenvolvedores devem encarar quando tentam utilizar a Serialização para JavaScript a partir da versão 3.5 do framework.

Muitas vezes você deve ter migrado uma aplicação sua da versão 2.0 para a versão 3.5 ou superior, e suas requisições Ajax, ou plugins JQuery, pararam de funcionar e você perdeu horas tentando resolver. Ou quando descobriu o motivo, entrou em pânico porque viu que deveria alterar o retorno de todas as suas chamadas para começar a tratar uma propriedade “d” nos seus retornos JSON.

Se vicê já se deparou com isso, vamos aos fatos!

Exemplificando

Vou fazer um código simples, um PageMethod que retorno o nome e a idade de uma pessoa, vamos ver o retorno na versão 2.0 do .Net e na versão 3.5 ou superior, e ver o que pode impactar nossa aplicação. Esse exemplo é igual ao do post anterior:

Meu código C# (PageMethod)

   1: [WebMethod]
   2: public static object ObterPessoa()
   3: {
   4:    return new { Nome = "Frederico", Idade = 25 };
   5: }

Meu código JavaScript:

   1: $().ready(function () {
   2:        $.ajax({
   3:            type: "post",
   4:            contentType: "application/json",
   5:            url: "Default.aspx/ObterPessoa",
   6:            success: retorno
   7:        });
   8:    });
   9:  
  10:    function retorno(data) {
  11:        alert(data.Nome + " - " + data.Idade);
  12: }

O resultado como esperado:

image

A comunicação no Fiddler, conforme o esperado (Clique para ampliar):

image

O que quero mostrar é que o resultado do JSON foi exatamente como o esperado:

{"Nome":"Frederico","Idade":25}

E se eu mudar para o site na versão 3.5? Sem alteração nenhuma de código, meu alerta ficará assim:

image

E o Fiddler mostraria o problema (clique para ampliar):

image

Novamente, repare no JSON retornado:

{"d":{"Nome":"Frederico","Idade":25}}

Repare que agora, o .Net adicionou uma propriedade “d” no objeto, e todo o meu retorno está dentro dessa propriedade “d”.

Isso pode gerar muitos problemas. Imagine que você utilize um plugin Autocomplete, que espera uma lista de itens, e ao invés disso ele recebe um objeto apenas com uma propriedade “d” que por sua vez tem uma lista de itens.

Isso pode gerar grandes impactos em códigos. Veja, para meu simples código funcionar eu já teria que mudar o meu método que trata o retorno, para ficar da seguinte forma:

   1: function retorno(data) {
   2:    alert(data.d.Nome + " - " + data.d.Idade);
   3: }

E finalmente o alerta paracer como o esperado:

image

Veja que tive que adicionar o “d”. Imagine agora no impacto se você estiver utilizando JQGrid, tendo que adicionar o mapa para o D em todos os seus JSONReaders.

Agora que entendemos o problemas, vamos aos motivos

A Microsoft resolveu implementar essa alteração na forma de serialização para resolver um problema de segurança, conhecido como JSON Hijacking, que consiste em um hacker interceptar uma requisição JSON e alterar o comportamento de sites mediante requisições desse tipo, lendo e escrevendo informações de forma anônima, como se fosse outra pessoa. Como o objetivo do post não é falar dos motivos, você pode ver mais informações sobre isso nos links abaixo (Uma rápida busca no Google por JSON Hijacking pode te dar outros resultados).

http://haacked.com/archive/2009/06/25/json-hijacking.aspx

http://www.thespanner.co.uk/2011/05/30/json-hijacking/

http://www.openajax.org/whitepapers/Ajax%20and%20Mashup%20Security.php

Resolvendo o problema com JQuery

Como é muito provavel que qualquer controle Ajax da própria Microsoft ou do AjaxToolkit já esteja preparado para essa alteração do “d”. O foco da solução é para o mundo JQuery. A maior parte dos problemas ocorre com plugins, então como podemos solucionar esse problema de forma geral, uma vez por todas, para todos os plugins?

Simples, usando uma técnica que já vimos no último post: Definindo informações padrões do método ajax do JQuery.

Utilizaremos o método ajaxSetup para definir um filtro a todo retorno que recebermos de requisições assíncronas iniciadas pelo JQuery ou qualquer pluigin baseado nele, como o JQGrid e Autocomplete, citados nesse post.

O método Ajax do JQuery faz uso de um evento chamado dataFilter, responsável por fazer qualquer tratamento nos dados retornados do servidor no momento em que a resposta chega, antes mesmo de ser repassado para qualquer plugin que esteja invocando o método. Nesse evento nós podemos fazer o tratamento necessário e retirar a propriedade “d”. Vejamos um código

   1: $.ajaxSetup({
   2:    dataFilter: function (data, type) {
   3:    
   4:        if (type == "json" || type == undefined) {
   5:            var msg = eval('(' + data + ')');
   6:            if (msg.hasOwnProperty('d'))
   7:                return JSON.stringify(msg.d);
   8:            else
   9:                return data;
  10:        }
  11:        else return data;
  12:    }
  13: });

Veja que nesse código, eu verifico o tipo do retorno, e se ele for JSON (ou se não foi especificado eu considero que é JSON) eu transformo em um objeto JavaScript normal (eval), verifico se tem o “d” e se tiver, utilizo o valor do “d” com retorno, se não tem o “d” ou não é JSON eu retorno o próprio valor retornado do servidor.

Para fazer funcionar, adicionei um referência ao arquivo “json2.js”, que pode ser encontrado no Google, e desta forma essa biblioteca fica responsável por transformar meu objeto sem o “d” em JSON novamente. Obs.: Essa biblioteca só é necessária em navegadores mais antigos.

Eu só preciso configurar esse método uma vez, no arquivo MasterPage ou Layout (para MVC), por exemplo, e todas as requisições já estarão configuradas para funcionar utilizando esse método.

Caso você queira apenas utilizar esse método em uma única requisição ajax, pode passá-lo como parâmetro do próprio método $.ajax().

E pronto! Seus plugins estarão funcionando no Asp.Net 3.5 ou superior, sem que você tenha que mudar qualquer código de plugin, ou seu próprio código “legado”.

Espero que possa ajudar como ajudou a mim. O código foi baseado em um código desse post do Encosia.

Abraços e até o próximo!

23. agosto 2011 20:45 by Frederico B. Emídio | Comments (1) | Permalink

Invocando PageMethods diretamente com JQuery    

Olá pessoal!

Apesar de já ter tratado de PageMethods em um dos meus primeiros posts, vou falar um pouco mais dele novamente, porque vejo que muita gente ainda não entendeu com funciona, o que torna difícil a utilização do mesmo de outra forma que não seja através do proxy que o próprio Asp.Net cria no JavaScript.

Para entender o básico, veja o primeiro post sobre o assunto, para eu não precisar repetí-lo aqui.

Resumidamente, adicionamos um PageMethod criando um método estático em uma página, e decorando esse método com o atributo [WebMethod]. E no JavaScript acessamos esse método através do proxy no JavaScript da seguinte forma: PageMethods.[NomeDoMetodo].

Basicamente o Asp.Net disponibiliza o método como um WebService, e o JavaScript acessa o mesmo através da classe XmlHttpRequest.

Mas por que muitas vezes não conseguimos acessar esses métodos através do JQuery? Alguns Plugins como JQGrid e Auto-Complete as vezes têm certa dificuldade de conseguir enviar o chamado ou processar a resposta. Vamos a alguns exemplos.

Vou fazer um código bem simples, meu PageMethod vai ser assim:

   1: [WebMethod]
   2: public static string ObterPessoa()
   3: {
   4:     return "Retorno do Server";
   5: }

E meu JavaScript:

   1: $().ready(function () {
   2:     $.ajax({
   3:         url: "Default.aspx/ObterPessoa",
   4:         success:retorno
   5:     });
   6: });
   7:  
   8: function retorno(data) {
   9:     alert(data.d);
  10: }

Veja que o código é bem simples. Estou utilizando o mínimo do método ajax do JQuery, ou seja, os demais valores estão sendo utilizados os valores Default. Vendo o código, o retorno deveria uma alerta do JavaScript com o valor “Retorno do Server”. Mas a resposta é: Nada! Exatamente, nada acontece, inclusive não retorna erro algum.

Nesse momento é que o desenvolvedor começa a passar as mãos na testa e falar: “Maldito Murphy!”.

Se olharmos as chamadas o Fiddler ou outra ferramenta que monitora os Requests, teremos algumas informações interessantes. Na minha IE Developer Toolbar tenho as seguintes informações (clique para ampliar):

image

Perceba que na última linha tem a minha chamada para o PageMethod, sem erro, mas com um código diferente (304). Lembre que códigos de erros são apenas os 4xx e 5xx, ou seja, de fato não houve erro.

O HTTP Return Code 304 indica que o arquivo (ou resource) solicitado não teve alteração, ou seja, o Browser pode obter o valor do cache se quiser, ou solicitar a página mesmo assim. Então pense, se aparentemente é a primeira vez que estamos chamando o método, por que ele está falando que já está em cache? Qual será o retorno? Vamos dar uma olhada no retorno (clique para ampliar):

image

Veja que é o próprio código da página, e não do PageMethod, ou seja, o Asp.Net, ao receber o Request, está entendendo que o que está sendo solicitado é a página e não o método.

Isso acontece porque estamos invocando o método com o verbo HTTP GET, e a primeira coisa que devemos saber é que PageMethods só funciona com HTTP POST!

Outra coisa que podemos ver na primeira imagem, é que o tipo da solicitação é “text/html” e o retorno do Asp.Net está de acordo, ou seja, o texto HTML da página.

Portanto, a segunda coisa que devemos saber é que para o PageMethod funcionar é que o tipo da requisição deve ser json ou xml.

Vamos mudar apenas essas duas coisa e ver o que acontece:

   1: $().ready(function () {
   2:     $.ajax({
   3:         type: "post",
   4:         contentType: "application/json", 
   5:         url: "Default.aspx/ObterPessoa",
   6:         success:retorno
   7:     });
   8: });
   9:  
  10: function retorno(data) {
  11:     alert(data.d);
  12: }

E os prints da Developer Toolbar:

image

Veja que algumas coisas mudaram:

Primeiro que o método agora é POST e o código do retorno é 200, ou seja, sucesso (OK). Além disso, o tipo da requisição também mudou, sendo agora application/json. Só o fato dessas informações terem mudado já é alguma coisa. Mas vamos ver o retorno:

image

E o alerta, como o esperado.

image

Assim já fazemos nosso PageMethod funcionar. Poderíamos terminar o post por aqui, mas tem mais algumas coisas que precisamos saber, por exemplo, como eu passo parâmetros?

Passando parâmetros para PageMethods com JQuery

Vou mudar meu PageMethod e meu JavaScript para passar parâmetros. A alteração é muito simples, preciso apenas passar meu dados no formato JSON, assim o Asp.Net vai saber converter os dados do requests para os parâmetros do método. Vamos lá:

   1: [WebMethod]
   2: public static string ObterPessoa(string nome, string idade)
   3: {
   4:    return string.Format("Nome {0}. Idade {1}",nome,idade);
   5: }

E o JavaScript:

   1: $().ready(function () {
   2:    $.ajax({
   3:        type: "post",
   4:        contentType: "application/json",
   5:        url: "Default.aspx/ObterPessoa",
   6:        success: retorno,
   7:        data: '{nome:"Frederico",idade:"25"}'
   8:    });
   9: });
  10:  
  11: function retorno(data) {
  12:    alert(data.d);
  13: }

Dessa forma conseguimos passar os dados, e podemos ver com o alerta que o retorno foi como o esperado:

image

Conclusão

Vimos que é possível invocar PageMethods do JQuery sem muito esforço. Precisamos apenas saber quais parâmetros passar na chamada. Muitas vezes nossos plugins não funcionam com PageMethods porque não sabemos quais parâmetros utilizar. Uma vez que já sabemos, fica fácil.

Tenha em mente que para um PageMethod funcionar, você deve invocá-lo:

  • Utilizando o verbo Post
  • Utilizando o Content-Type como application/json.

Isso já é suficiente para funcionar.

Se você vai invocar muitas vezes métodos através do Ajax do JQuery, você pode alterar os valores Defaults e invocar de forma mais sucinta, da seguinte forma:

   1: $().ready(function () {
   2:     $.ajaxSetup({
   3:         type: "post",
   4:         contentType: "application/json"
   5:     });
   6:     
   7:     //E chamar sem precisar configurar novamente.
   8:     $.ajax({
   9:         url: "Default.aspx/ObterPessoa",
  10:         success: retorno,
  11:         data: '{nome:"Frederico",idade:"25"}'
  12:     });
  13: });

Essa tática é muito boa para utilizar com plugins, afinal, você não consegue (ou não deve) alterar a chamada internas dos plugins, como o JQGrid, então assim você alterar o padrão, para que o plugin utilize o método $.ajax da forma que você deseja.

O interessante de utilizar JQuery, é que você não precisa utilizar o ScriptManager com EnablePageMethods igual a true, porque você não precisará do Proxy do JavaScript. Sua página ficará consideravelmente mais leve se você tiver vários PageMethods em uma página só.

Em breve publicarei um breve post para explicar o porquê do “.d” no retorno do PageMethods, o que também muitas vezes dificulta a utilização de PageMethods com plugins JQuery.

Bom pessoal, espero que ajude. Até o próximo.

16. agosto 2011 09:32 by Frederico B. Emídio | Comments (1) | Permalink

Como utilizar validação com Asp.Net MVC    

Olá pessoal!

Hoje vou falar de uma tarefa importante no desenvolvimento de sites: Validação.

Na construção de site nós nunca podemos confiar nas informações que o usuário informa, devemos saber que qualquer pessoa pode errar uma digitação ou esquecer de digitar uma informação qualquer, e por isso é importante saber utilizar Validação nos formulários que criamos.

No Asp.Net MVC existem várias formas de realizar validações, mas hoje vou falar de apenas três:

  • Adicionando informações à propriedade ModelState
  • Utilizando DataAnnotations
  • Utilizando DataAnnotations com JQuery

O processo de validação no Asp.Net MVC ficou muito fácil, eu diria que ficou muito mais fácil que no Asp.Net WebForm, vamos então começar pelo básico:

Validando suas Views com ModelState

A validação no Asp.Net MVC sempre é feita através do estado do modelo (ModelState) recebido na Action de um Controller, o que muda é como esse estado é alterado, pois pode feito manualmente, como faremos agora, ou automaticamente, através de ActionFilter customizado ou automático.

A forma básica é você adicionar manualmente informações de erro no modelo ao ModelState, invocando o método AddModelError(chave,mensagemDeErro).

Vamos aos exemplos! Para começar vou criar meu modelo, bem simples, como em todos os meus outros exemplos: Pessoa

   1:  public class Pessoa
   2:  {
   3:      public string Nome { get; set; }
   4:      public string Email { get; set; }
   5:      public string Telefone { get; set; }
   6:      public int Idade { get; set; }
   7:  }

Naturalmente, para criar uma pessoa no banco de dados, algumas informações devem ser obrigatórias e outras devem seguir algum formato específico, para todos os nossos exemplos usaremos as mesmas validações:

  • O nome é obrigatório.
  • O e-mail é obrigatório.
  • O telefone é obrigatório.
  • O e-mail deve seguir o formatado texto@texto.texto
  • A idade é deve ser maior que 18.
  • O telefone deve seguir o formato ####-####

Vou criar duas Actions de nome Edicao, uma para renderizar a View inicial e outra para persistir os dados, essa segunda terá a responsabilidade de fazer a validação do Modelo, e adicionar os erros ao ModelState. Caso não tenha erro, apenas redirecionará o usuário para a página inicial (persistir em uma base de dados não vem ao caso).

Abaixo segue o código das Actions:

   1:  public ActionResult Edicao()
   2:  {
   3:      return View();
   4:  }
   5:   
   6:  [AcceptVerbs(HttpVerbs.Post)]
   7:  public ActionResult Edicao(Pessoa pessoa)
   8:  {
   9:      //Valida os dados no lado do servidor.
  10:      if(string.IsNullOrEmpty(pessoa.Nome))
  11:      ModelState.AddModelError("Nome","Nome é obrigatório");
  12:      
  13:      if (string.IsNullOrEmpty(pessoa.Email))
  14:      ModelState.AddModelError("Email", "Email é obrigatório");
  15:      else{
  16:      if (!Regex.Match(pessoa.Email,@"^([a-zA-Z0-9_\-\.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([a-zA-Z0-9\-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$").Success)
  17:      ModelState.AddModelError("Email", "E-mail inválido.");
  18:      }
  19:   
  20:      if (pessoa.Idade <= 18)
  21:      ModelState.AddModelError("Idade", "Idade deve ser maior que 18.");
  22:   
  23:      if (string.IsNullOrEmpty(pessoa.Telefone))
  24:      ModelState.AddModelError("Telefone", "Telefone é obrigatório.");
  25:      else
  26:      {
  27:      if (!Regex.Match(pessoa.Telefone, @"^\d{4}[-]{1}\d{4}$").Success)
  28:          ModelState.AddModelError("Telefone", "Preencha um telefone no formato ####-####");
  29:   
  30:      }
  31:      //Verifica se algum erro acima falhou.
  32:      if (!ModelState.IsValid)
  33:      {
  34:      return View();
  35:      }
  36:      else
  37:      {
  38:      //Se estive certo só redireciono para a página inicial.
  39:      return Redirect("/");
  40:      }   
  41:  }

O código é bem intuitivo, caso tenha adicionado alguma mensagem de erro, a propriedade IsValid do ModelState retornará false, e o modelo estará inválido, assim eu retorno minha mesma View, que exibirá as mensagens de erros. Minha View fica da seguinte forma:

   1:  <%using(Html.BeginForm()){ %>
   2:  <p>
   3:  <%=Html.LabelFor(Model=>Model.Nome)%>
   4:  <%=Html.TextBoxFor(Model=>Model.Nome)%>
   5:  <%=Html.ValidationMessage("Nome")%>
   6:  </p>
   7:  <p>
   8:  <%=Html.LabelFor(Model=>Model.Email)%>
   9:  <%=Html.TextBoxFor(Model=>Model.Email)%>
  10:  <%=Html.ValidationMessage("Email")%>
  11:  </p>
  12:  <p>
  13:  <%=Html.LabelFor(Model=>Model.Telefone)%>
  14:  <%=Html.TextBoxFor(Model=>Model.Telefone)%>
  15:  <%=Html.ValidationMessage("Telefone")%>
  16:  </p>
  17:  <p>
  18:  <%=Html.LabelFor(Model=>Model.Idade)%>
  19:  <%=Html.TextBoxFor(Model=>Model.Idade)%>
  20:  <%=Html.ValidationMessage("Idade")%>
  21:  </p>
  22:  <p>
  23:  <input type="submit" value="Salvar"/>
  24:  </p>
  25:  <%} %>

Veja que a única novidade da minha View a utilização do HTMLHelper ValidationMessage, passando o nome da chave que eu valido no servidor. Ao executar minha tela, caso passe informações inválidas, terei o seguinte resultado:

image

Ou assim:

image

E a sua validação está pronta para ser usada! Eu poderia utilizar um ValidationSummary, apenas utilizando o helper para isso, da seguinte forma: <%=Html.ValidationSummary()%>.

Vamos à nossa segunda forma de validar nosso modelo.

Validando suas Views com DataAnnotarions

DataAnnotations é uma forma de você adicionar validações ao seu modelo através de atributos, incorporada ao .Net 4. O interessante dessa estratégia é que não está ligada ao Asp.Net MVC, portanto, você pode utilizá-la tanto em Asp.Net, como em qualquer outra tecnologia .Net, como WCF. Isso é muito importante, pois você não precisa repetir validação em diversas partes do código, técnica conhecida como DRY (Don’t Repeat Yourself).

Como a validação é centralizada no modelo, nosso modelo sofrerá uma pequena alteração, assim como nossa Action, pois tiraremos a validação da Action e passaremos para o modelo. Nosso modelo ficará assim:

   1:  public class Pessoa
   2:  {
   3:      [Required(ErrorMessage = "O Nome é obrigatório.")]
   4:      public string Nome { get; set; }
   5:   
   6:      [Required(ErrorMessage = "O E-mail é obrigatório.")]
   7:      [RegularExpression(@"^([a-zA-Z0-9_\-\.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([a-zA-Z0-9\-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$", ErrorMessage = "E-mail inválido.")]
   8:      public string Email { get; set; }
   9:   
  10:      [Required(ErrorMessage = "O Telefone é obrigatório.")]
  11:      [RegularExpression(@"^\d{4}[-]{1}\d{4}$", ErrorMessage = "Telefone inválido. Informe ####-####.")]
  12:      public string Telefone { get; set; }
  13:   
  14:      [Range(18, Int16.MaxValue, ErrorMessage = "A idade deve ser maior que 18 anos.")]
  15:      public int Idade { get; set; }
  16:  }

Veja que existem vários tipos de atributos de Validação, e para todos eu posso informar uma mensagem de erro personalizada, através da propriedade ErrorMessage, além de cada um ter propriedades específicas de acordo com o tipo.

Como toda a lógica de validação passou para o modelo, nossa Action ficará bem mais simples:

   1:  [AcceptVerbs(HttpVerbs.Post)]
   2:  public ActionResult Edicao(Pessoa pessoa)
   3:  {
   4:      //O modelo já chega validado
   5:      if (!ModelState.IsValid)
   6:      {
   7:      return View();
   8:      }
   9:      else
  10:      {
  11:      //Se estive certo só redireciono para a página inicial.
  12:      return Redirect("/");
  13:      }
  14:  }

Veja como ficou simples a Action agora, e o resultado nas Views é o mesmo, não mudei nada no meu HTML, apenas adicionei um Summary, para ver que o resultado é o mesmo:

image

E mais uma forma de validação já está funcionando e pronta para publicar!

Mas espera aí! Existe um problema nessas duas formas de validação: Ela são realizadas no servidor. Ou seja, o usuário precisa ser submetido ao servidor para realizar a validação, o que pode prejudicar muito a experiência do usuário, e para isso termos a terceira forma de validação de hoje:

Utilizando DataAnnotations com JQuery para validação no Cliente

O mais interessante da utilização do JQuery com DataAnnotation é o impacto no código do servidor: Nada! Isso mesmo, não tem impacto nenhum no servidor para você adicionar validação no Asp.Net MVC no cliente. Vou fazer a seguinte alteração no HTML:

 

   1:  <% Html.EnableClientValidation();%>
   2:  <%using (Html.BeginForm())
   3:  { %>
   4:  <p>
   5:  <%=Html.LabelFor(Model=>Model.Nome)%>
   6:  <%=Html.TextBoxFor(Model=>Model.Nome)%>
   7:  <%=Html.ValidationMessageFor(Model => Model.Nome)%>
   8:  </p>
   9:  <p>
  10:  <%=Html.LabelFor(Model=>Model.Email)%>
  11:  <%=Html.TextBoxFor(Model=>Model.Email)%>
  12:  <%=Html.ValidationMessageFor(Model => Model.Email)%>
  13:  </p>
  14:  <p>
  15:  <%=Html.LabelFor(Model=>Model.Telefone)%>
  16:  <%=Html.TextBoxFor(Model=>Model.Telefone)%>
  17:  <%=Html.ValidationMessageFor(Model => Model.Telefone)%>
  18:  </p>
  19:  <p>
  20:  <%=Html.LabelFor(Model=>Model.Idade)%>
  21:  <%=Html.TextBoxFor(Model=>Model.Idade)%>
  22:  <%=Html.ValidationMessageFor(Model => Model.Idade)%>
  23:  </p>
  24:  <p>
  25:  <input type="submit" value="Salvar" />
  26:  </p>
  27:  <%} %>

As alterações na view foram pequenas, adicionei o Helper EnableClientValidation e mudei ValidationMessage por ValidationMessageFor, fora isso, foi necessário adicionar referência a alguns arquivos JS (JavaScript), você pode adicionar tanto no seu arquivo de Layout  (Master) ou na própria View. Os arquivos são os seguintes:

 

   1:  <script src="<%=Url.Content("~/Scripts/jquery-1.4.1.min.js")%>" type="text/javascript"></script>
   2:  <script src="<%=Url.Content("~/Scripts/jquery.validate.js")%>" type="text/javascript"></script>
   3:  <script src="<%=Url.Content("~/Scripts/MicrosoftMvcJQueryValidation.js")%>" type="text/javascript"></script>
 

Os arquivos que adicionei são os arquivo do próprio JQuery (a versão desatualizada que vem com o Visual Studio 2010, que você pode mudar para a atual), o plug-in Validate do Jquery e um arquivo fornecido pelo time do Asp.Net para fazer o meio campo entre a validação do Asp.Net com o JQuery de forma totalmente transparente. Esse arquivo pode ser baixado com o Asp.Net MVC Futures, clicando aqui.

O Resultado é o mesmo:

image

E assim sua validação já estará funcionando no cliente. O mais legal dessa abordagem é que você realizará a validação tanto no Cliente como no Servidor, sem repetir uma linha de código (DRY).

No servidor que eu digo não é como no WebForm, onde a validação de um Validator Control também funciona tanto no servidor como no cliente, porque naquele caso, é apenas no servidor Asp.Net, visto que a validação está na página. Nesse caso, a validação está no Modelo, logo, o mesmo código pode ser utilizado em uma classe de negócio, WCF, WWF, etc; sem replicação de código.

Existe uma validação nativa no lado do Cliente no MVC, mas preferi mostrar com o Jquery, porque é possível integrar outros plug-ins com a validação, que podem gerar efeitos bem interessantes à sua página.

Bom, acredito que seja o suficiente para você adicionar validação ao sua página, de forma bem clara sem ter que se esforçar muito.

Abaixo você pode baixar uma solução contendo três projetos, um com cada tipo de validação, para você ver que não existe grandes diferenças entra elas.

Abraços e até o próximo pessoal.

ValidatorsMVC.zip (1,00 mb)

27. fevereiro 2011 06:06 by Frederico B. Emídio | Comments (0) | Permalink

Utilizando Ajax com Asp.Net MVC    

Olá pessoal, hoje vou falar de um assunto que é de extrema importância para desenvolvimento Web atualmente: Ajax.

Para quem não sabe, Ajax é o acrônimo de Asynchronous Javascript And XML, e que na  prática nada mais é que a capacidade de postar informações ao servidor, sem a necessidade de enviar a página inteira, e receber apenas uma pequena informação, sem a necessidade de atualizar a página toda. Para saber mais, clique no link do nome.

Hoje em dia, Ajax virou praticamente um conceito de atualização parcial de páginas Web, digo isso, porque Ajax em si não é mais utilizado na grande maioria das vezes! É isso mesmo, se reparar no nome completo, o X do Ajax é XML, e normalmente não utilizamos XML para a comunicação, mas sim JSON, ou seja, o que utilizamos de fato é chamado muitas vezes em blog e artigos pela Web de AJAJ (Asynchronous Javascript And JSON).

A responsabilidade de fazer a comunicação de forma assíncrona é do navegador, através do objeto XMLHttpRequest (IE 7+, e demais browsers) ou do Microsoft.XMLHTTP (IE 5 e 6). No nosso caso, não precisamos saber disso, porque utilizaremos JQuery para encapsular toda a lógica de criação da comunicação.

Apesar de usarmos JQuery, nós poderiamos utilizar outros frameworks JavaScript para encapsular a lógica de comunicação. A própria Microsoft disponibilizar nos projetos Web o framework MicrosoftAjax.js, que é extremamente bom. Com esse framework, inclusive, você pode acessar funcionalidades do Asp.Net, como a parte de Authentication.

Bom, mas vamos ao que interessa.

Utilizando JQuery para fazer chamadas assíncronas em Asp.MVC

No Jquery existe uma forma básica de se comunicar assincronamente com o servidor, que é o método $.ajax. Este método contém todas as informações necessárias para uma comunicação, nele você pode definir a url, o método de retorno em caso de sucesso e em caso de falha, tipo do dado passado (onde você pode passar uma sério de Content-Type, como json, xml, text, etc), verbo HTTP (get, post, etc), e mais uma série de opções. Como não utilizaremos esse método, você pode clicar aqui para ver uma lista detalhada de opções.

Não utilizaremos esse método, porque existem dois métodos que abstraem bastante a utilização dele, e que são suficientes para a maioria das situações, são os métodos $.post e $.get.

Estes métodos basicamente invocam o método $.ajax, passando no parâmetro type o tipo post ou get. O único problema é que ele não retorna erro, ou seja, se tiver algum problema no seu código que faça ter algum erro, você vai ficar sem saber até quebrar um pouco a cabeça, o ideal é: Quando tiver algum comportamento estranho, mude o método para $.ajax, e defina o parâmetro error, assim poderá ver qual a mensagem de erro está sendo retornada do servidor.

Nosso site fará quatro testes:

  • Obter informação do servidor via Get
  • Enviar informação para o servidor via Get
  • Enviar informação para o servidor via Post através de parâmetros
  • Enviar informação para o servidor via Post através de um objeto.

Abaixo segue o código do Controller com suas Action:

   1:  public JsonResult ObterGet()
   2:  {
   3:      var json = new { Nome = "Nome do Servidor", Idade = 20 };
   4:      return Json(json, JsonRequestBehavior.AllowGet);
   5:  }
   6:   
   7:  public JsonResult EnviarGet(string nome, int idade)
   8:  {
   9:      var json = new { Nome = nome + " Servidor", Idade = idade + 1 };
  10:      return Json(json, JsonRequestBehavior.AllowGet);
  11:  }
  12:   
  13:  public JsonResult EnviarPost(string nome, int idade)
  14:  {
  15:      var json = new { Nome = nome + " Servidor", Idade = idade + 1 };
  16:      return Json(json);
  17:  }
  18:   
  19:  public JsonResult EnviarObjeto(Pessoa p)
  20:  {
  21:   
  22:      p.Nome += " Servidor";
  23:      p.Idade += 1;
  24:      return Json(p);
  25:  }

Os códigos são bem simples: Os métodos de GET (ObterGet e EnviarGet) precisam passar uma informação a mais no método Json pois o MVC força você a dizer que quer retornar uma chamada get, mesmo sabendo do risco que isso pode ser. É um risco porque um site de outro domínio pode invocar esse método utilizando GET, e se você não informar que isso aconteça, o ASP.NET vai barrar a chamada, retornado  a mensagem:

This request has been blocked because sensitive information could be disclosed to third party web sites when this is used in a GET request. To allow GET requests, set JsonRequestBehavior to AllowGet.

Como queremos testar o Get, então permitimos essa comunicação, adicionando o parâmetro JsonRequestBehavior.AllowGet. Para os métodos utilizados através de POST (EnviarPost e EnviarObjeto) não precisamos utilizar esse parâmetro.

Para o método EnviarObjeto funcionar, criei uma classe simples, que segue abaixo:

   1:  public class Pessoa
   2:  {
   3:      public string Nome { get; set; }
   4:      public int Idade { get; set; }
   5:  }

Para consumir esses métodos, criei o HTML abaixo:

<p>Nome:<input type="text" id="txtNome" /></p>
<p>Idade:<input type="text" id="txtIdade" /></p>
<input type="button" value="Enviar Get" onclick="enviarGet();"/>
<input type="button" value="Enviar Post" onclick="enviarPost();"/>
<input type="button" value="Enviar Objeto" onclick="enviarObjeto();"/>
<input type="button" value="Obter" onclick="javascript:obter();"/>

Sua visualização será essa:

image

E o Javascript da página será:

   1:  function obterCallback(retorno,status) {
   2:      $("#txtNome").val(retorno.Nome);
   3:      $("#txtIdade").val(retorno.Idade);
   4:  }
   5:  function obter() {
   6:      $.get("Ajax/ObterGet", obterCallback);
   7:  }
   8:   
   9:  function enviarGet() {
  10:      if ($("#txtNome").val() == "" || $("#txtIdade").val() == "") {
  11:          alert("Preencha todas os campos!");
  12:          return;
  13:      }
  14:      $.get("Ajax/EnviarGet",
  15:      { nome: $("#txtNome").val(), idade: $("#txtIdade").val() },
  16:         obterCallback
  17:      );
  18:  }
  19:   
  20:  function enviarPost() {
  21:      if ($("#txtNome").val() == "" || $("#txtIdade").val() == "") {
  22:          alert("Preencha todas os campos!");
  23:          return;
  24:      }
  25:      $.post("Ajax/EnviarJson",
  26:      { nome: $("#txtNome").val(), idade: $("#txtIdade").val() },
  27:         obterCallback
  28:      );
  29:  }
  30:   
  31:  function enviarObjeto() {
  32:      if ($("#txtNome").val() == "" || $("#txtIdade").val() == "") {
  33:          alert("Preencha todas os campos!");
  34:          return;
  35:      }
  36:      $.post("Ajax/EnviarObjeto",
  37:      { nome: $("#txtNome").val(), idade: $("#txtIdade").val() },
  38:         obterCallback
  39:      );
  40:  }

O JavaScript, utilizando o Jquery, é tão simples que nem precisaria de explicação, mas vamos lá: O primeiro parâmetro é o endereço da Action (Controller/Action), o segundo pode ser o método de retorno (Callback) ou os parâmetros que serão passados, caso seja definido parâmetro, o terceiro método é o método de retorno. Existe um quarto parâmetro que não estou utilizando, que seria para informar o tipo do retorno (json, xml, etc). No meu caso não preciso utilizá-lo.

Os parâmetros estou passando através de um objeto JSON, que o Jquery converte em querystring, caso seja GET ou coloca os parâmetros no corpo da mensagem HTTP, caso seja POST. Relembre essas regras aqui.

Para conseguir testar, basicamente eu altero o valor enviado para o servidor e retorno, preenchendo os campos com o novo valor, dessa forma posso ver que as informações estão realmente chegando no servidor e voltando.

Obervação: A Action que recebe as chamadas Assíncronas não precisa estar no mesmo Controller que retornou a View do formulário.

Conclusão

Quis mostrar nesse post como é simples utilizar Ajax juntando MVC e JQuery, tão simples quanto utilizar PageMethods no WebForms, porém, sendo mais rápido para primeira renderização (porque não precisa de ScriptManager para gerar um Proxy).

Obervação 2: No WebForms é possivel utilizar esses métodos do Jquery com os métodos estáticos da página marcados com o atributo WebMethod, dessa forma você não precisaria utilizar o ScriptManager para gerar o próximo PageMethods.

Acho importante esse tipo de conhecimento, pois hoje em dia não existe site ou sistema sem alguma funcionalidade Assícrona, e isso pode ser incluído nos conhecimentos básicos de Asp.Net MVC.

O Link para o exemplo está abaixo.

MvcAjax.zip (292,92 kb)

Bom, por hoje é isso. Até o próximo.


  
     
  
24. janeiro 2011 23:31 by Frederico | Comments (3) | Permalink

Tarefas Básicas com Asp.Net MVC Pt. III–Grid com plugin JQuery JQGrid    

 

Olá Pessoal!

Depois de um longo tempo sem escrever, devido a um projeto atrasado, vou finalizar a série sobre tarefas básicas com Asp.Net MVC.

Você viu neste e neste post como criar um cadastro em MVC. Porém, eu criei um grid muito simples, apenas usando as simples tags TABLE do HTML. Quando um iniciante em MVC vê isso, ele já se pergunta: “Mas e todas aquelas facilidades do GridView? Vou ter que criar na mão?”. A resposta é não. Existem muitas grids por ai que funcionam muito bem com Asp.Net MVC, e hoje vou mostrar como utilizar a que eu mais gosto, inclusive em WebForms (exatamente, eu não uso GridView a muito tempo).

A Grid que vou apresentar é um plugin Jquery muito bem feito, chamado JQGrid. Esse plugin tem constantes atualizações, com melhorias e correções, além de ter muitas referências na Web. O próprio site do plugin tem uma parte Wiki com todo o conteúdo necessário para você fazer tudo o que for necessário em um sistema, desde a simples grid com paginação até a SubGrid, Agrupamento, Edição inline, edição em popup,  entre muitas outras coisa, tudo em poucas linhas de códigos. As funcionalidades são separadas em módulos, e você pode baixá-los separadamente. Dê uma olhada aqui que você verá quantas possibilidades existem nesta grid. Além disso, o layout da grid é baseado nos temas do JQuery UI, ou seja, criar temas para grid é muito fácil a partir do site do JQuery UI

O objetivo deste post não é explicar amplamente o plugin, apenas mostrar como pode ser feita a integração com uma Action, a partir daí, muito mais pode se feito.

Então vamos lá!

Instalando o Plugin JQGrid

Para baixar a última versão, você pode acessar aqui. Nessa tela, você poderá selecionar quais módulos da grid deseja baixar, no meu caso eu vou selecionar todos, mas você pode ver com mais atenção quais são realmente necessários para um projeto real. Quanto mais módulos, maior o arquivo, e na internet isso ainda faz uma diferença.

Quando baixamos o Plugin, temos uma pasta src, que você pode estudar para ver como a Grid funciona, mas para adicionar em nosso site, precisamos apenas adicionar o arquivo jquery.jqGrid.min.js, que conterá tudo necessário para a Grid rodar. Além desse arquivo, existe também uma pasta chamada i18n, onde você encontrará arquivos de linguagens, adicione a que você achar melhor, eu vou adicionar apenas o arquivo de Português do Brasil.

Adicionado os arquivos de Scripts, você deve também adicionar os arquivos de layout (CSS). Dois arquivos devem ser adicionados, o CSS da Jquery UI, que pode ser baixado aqui, e o arquivo que complementa o CSS do UI, que vem com o download do JQGrid, chamado ui.jqgrid.css

Meu projeto (o mesmo do artigo anterior) ficará assim:

image

image

Após adicionarmos os arquivos ao nosso projeto, devemos adicionar a referência no HTML, tanto para os JS’s como para os CSS’s. Vou fazer isso na View Index, onde tenho a tabela HTML:

<link rel="Stylesheet" href="../../Content/jquery-ui-1.7.2.custom.css" />
<link rel="Stylesheet" href="../../Content/ui.jqgrid.css" />
<script type="text/javascript" src="../../Scripts/jquery-1.4.1.js"></script>
<script type="text/javascript" src="../../Scripts/i18n/grid.locale-pt-br.js"></script>

Como todo plugin Jquery, a configuração da Grid é feito pelo seu construtor, em cima de alguma tag do HTML selecionado pelo seletor do JQuery. Para criar a Grid, utilizei o seguinte código, em cima da table com id=table:

<script type="text/javascript">
$().ready(function () {
    $("#table").jqGrid({
    multiselect: false,
    datatype: "json",
    url: "Listar",
    colNames: ['Nome', 'Email', 'Telefone'],
    colModel: [
    { name: 'Nome', index: 'Nome', width: 100 },
    { name: 'Email', index: 'Email', width: 300 },
    { name: 'Telefone', index: 'Telefone', width: 80 }
     ],
    height: 220,
    caption: "Resultado",
    pager: "#pager",
    jsonReader: { repeatitems: false, id: "Codigo" },
    rowNum: 10,
    sortname: 'NomeEmpresa',
    sortorder: "asc",
    viewrecords: true
    });
 
});
        
</script>
<table id="table"></table>
<div id="pager"></div>

Vou explicar resumidamente alguns parâmetros, mas se você quiser uma explicação mais detalhada de cada opção, acesse a página do plugin, clicando aqui ou na wiki do site, vamos la:

Parâmetro Descrição
datatype Indica que tipo de dado a grid deve tratar, pode ser JSON, XML, local, entre outros.
url Método no servidor que realizará a pesquisa, no caso a Action, poderia ser uma WebService ou um PageMethods do WebForms. Se o tipo do dado for local, você não precisa desse parâmetro.
colNames Nome (Header) de cada Coluna, se você tiver uma coluna sem nome, só com um checkbox, por exemplo, você deve informar espaços em brancos, a quantidade de itens em ColNames deve ser igual a quantidade de colunas no ColModel
colModel Aqui é onde você define como será cada coluna, as opções são inúmeras, então visite o site para ver mais.
pager Indica em qual controle o plugin criará os controles de paginação. Geralmente é uma div, como no exemplo. Existem muitas opções de pager também, visite o site!
jsonReader Informa a estrutura que os dados devem vir do servidor, e qual é o ID dos dados. A variação também é ampla, estou usando o default.

 

A grid acima ficaria como a imagem abaixo.

image

Usando apenas as configurações padrões, minha grid já é totalmente funcional, com paginação e ordenação por coluna. Como disse, cada opção abre uma grande gama de opções, o site do plugin é bem completo e minha intenção não é replicar o site aqui, apenas apresentar a Grid.

Essas configurações delegam a responsabilidade de paginação e ordenação no servidor, mudando um pouco você poderia ter a ordenação e paginação controlada pela própria Grid, porém, é lógico que é muito mais rápido (no sentido de desempenho em tempo de execução) fazer isso tudo no servidor, além de poupar muito a banda de internet transferindo apenas os dados que serão exibidos para o cliente.

Minha action Listar ficou assim (Implementei apenas a paginação para demonstração, o código naturalmente não é um código de produção, afinal, a idéia é apresentar a grid):

[Obs: Código alterado para correção da lógica]

   1:  {
   2:      using (var bd = new bdEntities())
   3:      {
   4:      var query = from pessoas in bd.Pessoa 
   5:              select pessoas;
   6:      var ini = (page - 1) * 10;
   7:      var fim = query.Count()> 10? 10: query.Count();
   8:      if (ini > 0)
   9:      {
  10:          fim = 10;
  11:          fim = fim - 10 >= 0 ? query.Count() % 10 : fim;
  12:      }
  13:   
  14:      var totalPags = query.Count() / 10;
  15:      if (query.Count() % 10 > 0)
  16:      {
  17:          totalPags++;
  18:      }
  19:      var jsonData = new
  20:      {
  21:          total = totalPags, // número de páginas retornadas no reader
  22:          page = page,
  23:          records = query.Count(), // número total de registros na base.
  24:          rows = query.ToList().GetRange(ini,fim)
  25:      };
  26:      return Json(jsonData, JsonRequestBehavior.AllowGet);
  27:      }
  28:  }

Algumas considerações ao código:

Minha Action retorna um JsonResult, afinal é um objeto Json que minha grid espera. O método Json fica responsável por converter meu objeto jsonData em Json. Apesar de eu estar criando a variável jsonData como um objeto dinâmico, eu poderia definir essa classe como uma classe concreta, e utilizar os parâmetros por toda a aplicação, é assim que costumo fazer.

As propriedades do jsonData seguem um padrão nomes de acordo com o definido no jsonReader (parâmetro da Grid), se você mudar alguma coisa no padrão do jsonReader terá que mudar também nas propriedades de retorno, mais uma vez: todas essas inúmeras possibilidades estão no site do plugin.

Os parâmetros da Action também devem seguir essa assinatura, para que o Asp.Net consiga traduzir os parâmetros vindo do JavaScript diretamente para os parâmetros. Você pode mudar  essas regras com um pouco mais de programação, que, alias, eu acho uma boa idéia se você estiver pensando em adotar a Grid como padrão de lista para seus sistemas, quanto menos parâmetros, mais rápido para desenvolver!

A lógica de paginação não faz parte da solução, é claro.Alegre

Conclusão

A idéia desse post foi apresentar o plugin JQGrid, e mostrar que o mundo sem server controls não é tão difícil assim, eu já uso essa grid a muito tempo em WebForms, porque é uma solução muito mais poderosa e versátil que o GridView. Acredite em mim, cada nova possibilidade que você descobre nesse plugin, você fica mais fascinado e confiante.

O exemplo que mostrei, não mostrou nenhuma possibilidade do plugin, mas se você quiser ter uma noção da capacidade dele, clique aqui e veja com seus próprios olhos.

Para baixar o código do exemplo, clique link abaixo

Baixar Arquivo

20. janeiro 2011 23:55 by Frederico B. Emídio | Comments (3) | Permalink

Entendendo o JQuery ready() e live()    

Quando estamos aprendendo JQuery, a primeira coisa que aprendemos é que todo código de inicialização é colocado no método ready, porém, muitas vezes não nos perguntamos o porque isso é feito dessa forma.

Quem nunca viu um navegador lento renderizar a página toda torta e depois de alguns segundos sumir com tudo, deixando tudo organizado?

Com certeza isso é devido à má utilização do método ready(), ou desconhecimento do método live().

JQuery.ready(), como funciona?

Muitos pensam que o ready é executado quando a página é carregada por completo, porém, esse pensamento não está certo.

O JavaScript tem nativamente um método que é executado quando a página está carregada por completo, e esse método é o window.onload, que muitas vezes utilizamos na tag body através do evento onload. O método ready do JQuery não substitui esse método, e nem executa no mesmo instante.

Para o navegador a página está totalmente carregada quando todos os recursos da página estão carregados, e isso inclui todos os arquivos externos, como scripts, música e imagens. Apenas quando todos os recursos estão carregados o navegador invoca o evento Load da janela, ou seja, caso a página esteja carregando um script ou uma imagem muito grande, dependendo do navegador, toda a página pode ser exibida, porém, o Load pode não ser chamado ainda. (Obs.: Dependendo do navegador porque existem alguns navegadores que só exibem a página quando todos os recursos da página estão carregados em memória).

Diferente do Onload, o ready executa quando a estrutura do documento está pronta, ou seja, quando o DOM foi carregado por inteiro, mesmo que os recursos da página, como scripts e imagens, ainda não tenham sido carregados. Isso pode acontecer porque muitos navegadores modernos carregam os recursos de forma assíncrona, ou seja, exibe a página, apenas com CSS e texto, por exemplo, e vai carregando imagens paralelamente, sem impedir que o usuário possa começar a ler o conteúdo da página.

Já aconteceu comigo de utilizar um plugin JQuery que carregava os scripts necessários por demanda, e muitas vezes, ao chamar a criação do plugin no método ready, era retornado o erro O objeto não dá suporte para a propriedade ou método, isso porque o arquivo que continha o plugin que eu tentava chamar ainda não estava carregado. Portanto, se você carrega arquivos de forma dinâmica, o ready não é uma boa opção.

Caso seja realmente interessante carregar scripts dinamicamente, crie métodos com callbacks que indiquem que os arquivos já foram carregados, para ai sim você poder atribuir eventos e plugins aos controles.

JQuery.live(), quando usar?

Agora que já entendemos como funciona o método ready(), podemos conhecer o live().

Imagine que você realmente precise carregar algumas informações assíncronas para criar a tela, por exemplo, as informações para criar tabs carregam de um arquivo de acordo com um script de globalization, que é carregado depois que o navegador identifica a linguagem do browser, ou imagine que alguns trechos do seu HTML serão adicionados/carregados, depois que o DOM já está pronto, e portanto, depois que o ready já executou, ou você não quer correr o risco que um browser renderize o começo da página antes de montar todo o DOM, e o começo da página em vez de exibir suas tabs, exiba uma lista (LI) de palavras, pois o ready não executou ainda e você não pôde ligar os métodos dos plugins.

Essas situações podem acontecer e é aí que você utiliza o live.

O live() gerencia eventos em controles que são dinamicamente adicionados ou removidos de uma página, você pode utilizar a chamada live em controle que nem existem ainda, mas que virão a existir durante a vida da página.

Por exemplo, o código abaixo:

<script type="text/javascript">
$().ready(function () {
        $("input:button").click(function () {
            alert(this.value);
            $("<input value=""+$("input:button").length+"" type="button" />").appendTo("#div");
        });
    });
</script>
<div id="div">
    <input type="button" id="btnClick" value="Botao1" />
    </div>

O código acima, do jeito que está, dentro de um ready, sempre que for clicado no primeiro botão, será exibido um alerta com o value do botão, e adicionará um novo. Porém, ao clicar nos adicionados, nada acontecerá, porque uma vez adicionado evento ao botão na criação do DOM, nada mais vai acontecer, porém, com o método live, os controles adicionados dinamicamente também irão receber o evento.

O código ficaria assim:

 

 

<script type="text/javascript">
$("input:button").live("click",function () {
            alert(this.value);
            $("<input value=""+$("input:button").length+"" type="button" />").appendTo("#div");
        });
</script>
<div id="div">
    <input type="button" id="btnClick" value="Botao1" />
    </div>

Desta forma, sempre que for adicionado um novo controle, o novo controle automaticamente irá receber o evento. Isso pode ser muito útil para controle como grid, por exemplo.

Identificando todas as situações onde o live poderia ser utilizado, poderíamos tirar bastante processamento do ready, o que deixaria o processamento da página muito mais rápido, pois os eventos já seriam adicionados ao controle no momento da criação, não só quando o DOM fosse totalmente criados. Fora que mesmo que fossem criados dinamicamente, como exemplificado acima, os eventos já seriam adicionados, poupando alguma quantidade de código, e deixando o documento menor.

E um detalhe interessante, você pode adicionar vários eventos ao mesmo tempo com o live, apenas separando os nomes dos eventos com espaço, por exemplo:

$("input:button").live("mouseover mouseout",function () {...

Conclusão

Nem tudo que a gente aprende no começo é a melhor coisa a se fazer em todas as situações. Nesse post não consegui abordar todos os prós e contras do live e do ready, mas dando uma estudada melhor na biblioteca do JQuery vamos descobrir muitas coisas interessantes.

Vou voltar a falar mais coisas sobre essa biblioteca incrível nos próximos post, tentando sempre melhorar o conhecimento dos métodos que facilitam nossa vida no JavaScript.

Fica ai a dica!

Abraços e até o próximo post.

30. setembro 2010 04:33 by Frederico | Comments (5) | Permalink

DataBind na Web    

Para quem é programador WindowsForm, o conceito de DataBind é comum. Caso você não saiba muito do que estou falando, o conceito é bem simples:

Você define um DataSource em um Formulário, e com isso consegue atrelar um campo da fonte de dado a um campo do Formulário, fazendo que qualquer alteração que aconteça em uma das pontas, reflita na outra.

Isso pode ser muito útil, pois ajuda muito no tempo de desenvolvimento, visto que não é necessário codificar dois códigos, um para atribuir informações da fonte de dados aos campos da tela, e depois o caminho contrário.

Na Web esse tipo de conceito não é muito comum, mesmo que em WebForm você consiga adicionar DataSources a uma página, e utilizar DataBinders nos campos, o conceito é consideravelmente diferente, visto que a direção dos dados é apenas de Fonte de Dados para campos, e o caminho inverso deve ser feito manualmente.

Como adicionar DataBinders na Web

Bom, quem me conhece sabe que dificilmente eu iria  elogiar Windows Forms e criticar a Web desta forma. De fato, na minha opinião, o que a Web ainda tem que não é tão bom é a banda da internet, que é um problema que logo mais será resolvido no mundo. Quanto experiência do usuário, ou experiência de desenvolvimento, cada vez mais eu percebo que a Web não deixa nada a desejar, e tem ficado cada vez melhor, com HTML5, CSS 3, ou mesmo plugins como SilverLight ou Flash.

Mas o que quero falar aqui é da sensação dos últimos anos: JQuery, que pode ser baixada clicando aqui.

JQuery, segundo definição do próprio site, é uma biblioteca JavaScript que simplifica a transformação de HTML, manuseio de eventos da página, animação e interações de Ajax para desenvolvimento rápido para Web. JQuery é projetado para mudar a forma que você escreve JavaScript

Bela definição, e de fato JQuery é uma biblioteca poderosa que ajuda muito a controlar o comportamento de uma página Web. JQuery é uma biblioteca tão popular hoje em dia, que a própria Microsoft teve que abraçar, e agora ela já vem embutida nos projetos web do Visual Studio 2010.

A Microsoft, inclusive, tem incentivado o seu time de desenvolvimento a contribuir com o JQuery, e eles têm feito grandes feitos a pelo menos dois anos.

Hoje vou falar de uma das contribuições: Data Linking

Utilizando JQuery Data Linking para realizar Data Bind na Web

Data Linking é a forma que a Microsoft achou para realizar databing na Web, e o funcionando é extremamente satisfatório. Como no Windows Form, o funcionamento é bidirecional (fonte de dados para campos e vice-versa).

Seu funcionamento é simples, no padrão do JQuery: a partir de um objeto JSON, que pode ser retornado de um PageMethod, nós fazemos os binds com apenas uma linha de código.

Abaixo segue o código de uma página utilizando esse plugin:

 

<pre><script type=" src="jquery-1.4.2.js" javascript?="javascript?" text="text"></script>
<script type="text/javascript" src="jQuery.datalink.js"></script>

    <h2>
        Data Linking
    </h2>
    <p>
        Nome: <input id="txtNome" />
    </p>
    <p>
        Idade: <input id="txtIdade" />
    </p>
    <input id="btnClick" value="Ler" type="button" />
    <input id="btnScript" value="Alterar Via Script" type="button" /></pre>

<script type="text/javascript">

    var pessoa = { Nome: "Frederico", Idade: 24 };

    $("#btnClick").click(ler);

    $("#btnScript").click(function () {
        //Alterando programaticamente
        $(pessoa).attr("Nome", "Frederico Emídio");
    });

    function preencher() {
        //Definindo o bind.
        $(pessoa).linkBoth("Nome", "#txtNome", "val")
                .linkBoth("Idade", "#txtIdade", "val");
    }

    function ler() {
        alert(pessoa.Nome + ' - ' + pessoa.Idade);
    }

    preencher();
</script>

Os três parâmetros do método linkBoth são óbvios: Nome da propriedade do DataSource, nome do Controle, e método que deve ser usado para a realização do bind. (Obs.: Caso você queira apenas o bind na direção da fonte de dados para os controles, você poderia usar o método linkFrom, utilizando os mesmos parâmetros).

O resultado da página pode ser visto aqui. Neste exemplo você pode ver que as alterações, tanto feitas no código como nos campos são refletidas em ambos os locais.

Uma outra função também existe neste plugin, que é a de formatação das informações ao atribuir os valores nos campos, mas para o intuito deste post, o que foi mostrado já é o suficiente.

Clique aqui para baixar o plugin Data Link “beta”

Até o próximo post!


  
     
  
14. setembro 2010 09:50 by Frederico | Comments (1) | Permalink

Sobre mim

Minha Imagem

Meu nome é Frederico Batista Emídio, trabalho com desenvolvimento de sistemas profissionalmente a oito anos, porém, já faço sites pessoais a pelo menos dez anos.

Para saber mais clique aqui.

Páginas

Calendário

<<  novembro 2017  >>
seteququsedo
303112345
6789101112
13141516171819
20212223242526
27282930123
45678910

Visualizar posts em um Calendário
Sigua @fredemidio

MCP Asp.NET