Já ouviram falar em Data Binding, ViewModel, MVVM? Não? Então é hora de sair da caixinha e conhecer os mais novos recursos disponíveis do Ext JS.
Hoje vamos aprender um pouco sobre Data Binding e ViewModel no Ext JS e colocar em prática em um pequeno exemplo.
Data Binding e View Model (MVVM)
Partes destes recursos já existiam em vários frameworks JavaScript (Angular, Vue.js, entre outros), antes mesmo de lançarem no Ext JS, e para tornar mais completo ainda o framework, a Sencha implementou isso e muito mais a partir da versão 5.0 do Ext JS. Juntos traz muito poder ao framework e a você também.
Uma ViewModel é uma classe que gerencia um objeto de dados. Sendo assim, permite aqueles interessados nessa informação, vincular a ela e serem notificados quando houver mudanças, sem setBlaBlaBla() e getBlaBlaBla().
Os Componentes possuem a configuração bind que permite associar várias de suas próprias configurações aos dados do ViewModel. Usando bind , você pode ter certeza que a propriedade de configuração do componente terá seus métodos setter e getter chamados assim que os dados vinculados no ViewModel alterarem. Isso é fantástico, pois você irá evitar declarar vários listeners, chamar aquela tonelada de setText(), setVisible(), setDisabled() quando alguns dados mudarem.
Então pare tudo que está fazendo ai, e vamos conheçer esse grande recurso entre outros que está disponível no framework.
Januario me mostre um código pra eu entender melhor esse parangolé ai?
Ext.create('Ext.panel.Panel', { title: 'Simple Form', viewModel: { data:{ someWidth: 100, name: 'Wemerson Januario' } }, bind: { html: '<p>Hello {name}</p>', width: '{someWidth}' } });
Quando os valores das propriedades someWidth e name forem alterados no ViewModel, serão atualizados nos componentes que estão vinculados pelo bind , isso tudo automático e sem setWidth e setHtml . legal né?
Para entender melhor, no final deste artigo você terá alguns links para estudos e exemplos sobre ViewModel e Data Binding.
Nosso Caso de uso
Na maioria de nossas aplicações sempre precisamos de telas de pesquisa de endereço por CEP, e muito das vezes importamos um gigante banco de dados que achamos por ai ou então consumimos Webservices fornecidos de forma paga ou gratuita.
Agora que você pegou a moral de o que é o tal Data Binding, vamos desenvolver esse exemplo de forma rápida e fácil e com poucas linhas de código.
Topa?
Primeiramente vamos criar um formulário básico onde o usuário digite o CEP em um textfield e terá o formulário preenchido automaticamente com os dados retornados de serviço de terceiro que iremos consumir. Também vamos conhecer um pouco sobre esse”cara” que vai nos ajudar fazer isso fornecendo um webservice.
A ViaCep
é um webservice gratuito e de alto desempenho para consultar Códigos de Endereçamento Postal (CEP) do Brasil. Você pode utilizar este serviço a vontade, melhorando a qualidade de suas aplicações web e colaborar para manter esta base de dados atualizada.
Acessando o webservice de CEP
Para acessar o webservice, um CEP deve ser fornecido no formato “01001-000” ou “01001000“.
Após o CEP, deve ser fornecido o tipo de retorno desejado, que deve ser “json“, “xml“, “piped” ou “querty“.
Exemplo: http://viacep.com.br/ws/01001-000/json/
retornará um JSON assim:
{ "cep": "01001-000", "logradouro": "Praça da Sé", "complemento": "lado ímpar", "bairro": "Sé", "localidade": "São Paulo", "uf": "SP", "ibge": "3550308" }
Mão na massa
Vamos criar uma janela com um formulário simples contendo os campos: Cep, logradouro, número, complemento, bairro, cidade e estado.
var dialog = Ext.create('Ext.window.Window', { autoShow: true, bind: { title: 'Consultar CEP: {cep}' }, controller: 'myviewcontroller', viewModel: { data: { cep: '', endereco: null, numero: '', naoLocalizado: false }, formulas: { enderecoCompleto: function (get) { if (get('endereco.logradouro')) { return get('endereco.logradouro') + ' ' + get('numero') + ' ' + get('endereco.complemento') + ' ' + get('endereco.bairro') + ' ' + get('endereco.localidade') + ' ' + get('endereco.uf'); } } } }, width: 500, height: 400, items: [{ xtype: 'form', fieldDefaults: { labelAlign: 'top', style: 'margin-right: 5px;' }, bodyPadding: 10, items: [{ xtype: 'textfield', emptyText: '74000-000', reference: 'cep', enableKeyEvents: true, bind: '{cep}', listeners: { keyup: 'onCepKeyUp' }, fieldLabel: 'CEP' }, { xtype: 'container', bind: { visible: '{naoLocalizado}' }, html: '<div style="font-weight:bold; color:red;">Endereço não localizado. Favor entre manualmente.</div>' }, { xtype: 'container', layout: { type: 'hbox' }, items: [{ xtype: 'textfield', flex: 2, fieldLabel: 'Logradouro', reference: 'logradouro', bind: '{endereco.logradouro}' }, { xtype: 'textfield', flex: 1, fieldLabel: 'Número', reference: 'numero', bind: '{numero}' }, { xtype: 'textfield', flex: 2, fieldLabel: 'Complemento', bind: '{endereco.complemento}' }] }, { xtype: 'container', layout: { type: 'hbox' }, items: [{ xtype: 'textfield', fieldLabel: 'Bairro', flex: 2, bind: '{endereco.bairro}' }, { xtype: 'textfield', flex: 2, fieldLabel: 'Cidade', bind: '{endereco.localidade}' }, { xtype: 'textfield', flex: 1, fieldLabel: 'UF', bind: '{endereco.uf}' }] }, { xtype: 'fieldset', title: 'Data Binding Formulas', layout: { type: 'form' }, items: [{ xtype: 'displayfield', labelAlign: 'rigth', fieldLabel: 'Endereço completo', bind: '{enderecoCompleto}' }] } ] }] });
Perceba que definimos o ViewModel de forma literal no próprio componente da Window, mas também podemos definir em uma classe separada e usar o xtype posteriormente.
veja como:
Ext.define('MyViewModel', { extend: 'Ext.app.ViewModel', alias: 'viewmodel.myviewmodel', data: { cep: '', endereco: null, numero: '', naoLocalizado: false }, formulas: { enderecoCompleto: function (get) { if (get('endereco.logradouro')) { return get('endereco.logradouro') + ' ' + get('numero') + ' ' + get('endereco.complemento') + ' ' + get('endereco.bairro') + ' ' + get('endereco.localidade') + ' ' + get('endereco.uf'); } } } });
Criamos a classe do ViewModel com o alias myviewmodel , agora basta definir no componente assim:
var dialog = Ext.create('Ext.window.Window', { //configs here viewModel: { type: 'myviewmodel' } });
No ViewModel, definimos algumas propriedades que serão vinculadas através da configuração bind na view.
Vamos conhecer:
- cep (usada para guardar o CEP digitado no textfield e alimentar o titulo da Window conforme for digitando
- endereco (armazenará um objeto com os dados do endereço retornado pelo webservice)
- numero (armazenará o número que usaremos na formula “enderecoCompleto”)
- naoLocalizado (marcaremos essa flag com true ou false para sinalizar que encontrou ou não o endereço para o CEP consultado).
Criamos também uma formula que retorna uma string com o endereço completo, onde será usada no fieldset na parte inferior do form.
Vamos agora colocar gasolina no negócio e começar a brincar de MVVM, criando um ViewController para conter o método onCepKeyUp.
Eis aqui o ViewController:
Ext.define('MyViewController', { extend: 'Ext.app.ViewController', alias: 'controller.myviewcontroller', onCepKeyUp: function (field) { var me = this, vm = me.getViewModel(), cep = vm.get('cep'); vm.set('endereco', {}); vm.set('naoLocalizado', false); if (/^[0-9]{5}-[0-9]{3}$/.test(cep) || /^[0-9]{8}$/.test(cep)) { Ext.Ajax.request({ cors: true, useDefaultXhrHeader: false, url: 'https://viacep.com.br/ws/' + cep + '/json', success: function (response) { var webserviceResponse = Ext.decode(response.responseText); if (webserviceResponse.erro) { me.lookupReference('logradouro').focus(); vm.set('naoLocalizado', true); return; } vm.set('endereco', webserviceResponse); me.lookupReference('numero').focus(); }, failure: function(response, opts){ Ext.Msg.alert('Falha','Houve um erro na conexão com o servidor'); } }); } } });
Tendo o ViewController definido, já podemos linkar ele na view, como fizemos declaração do Window.
controller: ‘myviewcontroller’
A ideia é bem simples. Iremos chamar esse método quando o evento keyup do textfield do CEP for disparado. Sendo assim temos a seguinte lógica.
- Usaremos uma expressão regular para testar se o CEP digitado possui o seguinte formato “01001-000” ou “01001000“. Assim não usaremos recursos de rede desnecessariamente.
- Iremos consumir o webservice e instruir um retorno no formato json.
- No callback da requisição Ajax, verificamos se o retorno é um objeto com o endereço ou erro.
- Se encontrar algum endereço iremos dar foco no campo número.
- Se o retorno for erro, iremos alimentar a flag naoLocalizado com true, e como um toque de magica exibirá um container informando que o endereço não foi localizado e o foco será no campo logradouro.
Com apenas essas regras já colocamos o ViewModel pra trabalhar e consequentemente nossa formula para vincular o fieldset “Endereço completo” irá funcionar.
Ohhhhhh, (aplausos)! “Rapaz!!!! não é de ver que o trem funciona!”
Vale ressaltar que nesse caso, para nossa requisição Ajax funcionar corretamente, precisaremos habilitar 2 configurações no Ajax, sendo elas, cors e useDefaultHeader, isso porque estamos requisitando dados para outro domínio e por isso existe algumas seguranças. Leia mais sobre CORS para entender a fundo o conceito.
http://pt.wikipedia.org/wiki/Cross-origin_resource_sharing
O que aprendemos nesse artigo?
Você aprendeu como funciona Data Binding e ViewModel no Ext JS ou então compliquei totalmente sua cabeça, rsrs, vai desculpando ai. 😉
Na verdade mesmo, eu quis abordar um pouco sobre muita coisa que podemos fazer usando Ext JS, tais como:
- Data Binding.
- ViewModel
- ViewController
- Consumir Webservice
- Cors em Ajax
- Expressão regular
Fontes para estudos
O demo online do que vimos está aqui https://fiddle.sencha.com/#fiddle/nga
Exemplos de data binding http://dev.sencha.com/extjs/5.1.0/examples/kitchensink/#data-binding
Documentação do ViewModel http://docs.sencha.com/extjs/5.1/5.1.1-apidocs/#!/api/Ext.app.ViewModel
Documentação ViewController http://docs.sencha.com/extjs/5.1/application_architecture/view_controllers.html
Guia básico http://docs.sencha.com/extjs/5.1/application_architecture/view_models_data_binding.html
Webservice https://viacep.com.br/
CORS http://pt.wikipedia.org/wiki/Cross-origin_resource_sharing
Conclusão
Escreva menos códigos e potencialize suas aplicações, não tenha medo do novo e do complexo.
Quer dizer um oi e trocar ideias? Venha fazer parte da nossa comunidade no Slack e Fórum.
Não esqueça de cadastrar seu e-mail para receber atualizações do blog gratuitamente.
E ai, o que achou? Espero que seja útil esse artigo para vocês. um forte abraço e até a próxima.
4 Comentários. Deixe novo
Muito bom! Foi legal ver um pouco de EXT depois de tanto tempo! Obrigado!
Muito bom mesmo! Faz um minicurso aí, Wemerson!
Já está na minha agenda. Em breve. Obrigado
Excelente post meu caro. Muito obrigado por compartilhar conosco o seu conhecimento.