

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.