Olá pessoas, e programadores…
Nessa terceira e última parte do nosso tutorial de um sistema web de Lista de Tarefas usando Aurelia e TypeScript, vamos ver como rodar nosso sistema. Está pronto?
Lembrando que nosso tutorial é baseado exatamente no tutorial oficial, sendo uma tradução adaptada do mesmo: https://aurelia.io/docs/tutorials/creating-a-todo-app#setup.
Índice desse tutorial
- Tutorial Aurelia JS: criando um Todo List, parte 1/3. Nesse tutorial você saberá um pouco mais sobre o Aurelia, bem como configurará seu ambiente para o desenvolvimento desse tutorial.
- Tutorial Aurelia JS: criando um Todo List, parte 2/3. Nessa segunda parte do tutorial você começará a criar as classes TypeScript do projeto e já veremos como o Aurelia trabalha em conjunto com a linguagem sem interferir no seu código fonte.
- Tutorial Aurelia JS: criando um Todo List, parte 3/3. Na terceira e última parte do nosso tutorial da Lista de Tarefas em Aurelia, veremos o código funcionando, bem como uma conclusão sobre o Aurelia.
Se desejar, poderá consultar meu repositório no GitHub para ver o projeto pronto: https://github.com/WilliamZimmermann/todo-aurelia
Rodando nosso App
Como breve recapitulação, lembre-se que quase nada que nós fizemos até aqui foi com o Aurélia. Quase tudo que programamos até então foi escrito com código TypeScript puro. Agora que adicionamos o arquivo main ao nosso projeto e que especificamos qual módulo exporta o componente raiz para nossa hierarquia de UI (user interface), Aurelia já pode ser renderizado.
Para que possamos renderizar, precisamos criar uma view para o componente app. Aqui introduzimos a próxima convenção do Aurelia. Para criar uma view para qualquer classe, você só precisa criar um arquivo HTML com o mesmo nome que o seu módulo TypeScript. Só que nesse caso, você precisa utilizar a extensão .html. Dentro dessa view, você pode colocar um template HTML5 com as expressões de ligações de dados (conhecidas como data binding) declarando como a view deve renderizar uma instância da classe. Vamos iniciar com uma view bem básica do nosso app.
<template> <h1>${heading}</h1> </template>
Podemos observar algumas coisas aqui. Primeiro, todas as views são colocadas dentro de um elemento de Web Components chamado <template>. Segundo, você observou a sintaxe ${heading} ? Bem, dentro de uma view você tem acesso a todas as propriedades e métodos da classe instanciada que é associada com com aquela view, e você pode acessar esses métodos e propriedades dentro do conteúdo de qualquer elemento ou atributo usando a sintaxa ${nome-elemento}. Essa sintaxe cria uma one-way data-binding (ligação de dados de mão única, traduzindo literalmente) para a propriedade heading. Por “one-way“, queremos dizer que o fluxo de dados é unidirecional e somente mudanças na propriedade heading afetarão a View. Não há mão contrária ou reversa, da camada View para a camada View-Model.
PADRÕES DE APRESENTAÇÃO. Chamamos a classe de view associada de View-Model porque ela é um Model feito para aquela View. A maior parte do desenvolvimento em Aurelia utiliza o padrão Model – View – View-Model (MVVM). No entanto, Aurelia é flexível permitindo usar também padrões como Supervising Controller, Passive View e o amado MVC(Model – View – Controller), se desejado.
Ok, agora que temos uma view, estamos prontos para rodar nosso sistema. Para fazer isso, precisaremos iniciar um servidor web para servir nossa página index.html, podendo executá-la no navegador. Como você fará isso dependerá da tecnologia que você deseja usar. Vamos trabalhar com o seguinte cenário (no tutorial original, há mais os seguintes cenários: (1) Visual Studio 2015, (2) NodeJS com Yarn e (3) Firefox):
- NodeJS com NPM*. Para iniciar um simples servidor no diretório do projeto instale globalmente o comando http-server com o seguinte código em seu Terminal/Promt de Comando: $ npm install http-server -g. Em alguns ambientes talvez você precise dar o comando sudo antes do npm…. Uma vez instalado, certifique-se que você está dentro do diretório do projeto. Agora você poderá subir o servidor com o seguinte comando: http-server -o -c-1.
Quando você rodar o app, você deverá ver seu App renderizando sua propriedade heading, exibindo algo como:
Renderizar propriedades no HTML parece uma tarefa simples, não é? Mas o que dizer de trabalhar com entrada de dados pelo usuário? Vamos adicionar ao nosso arquivo app.html algumas marcações que permitirão coletar esses dados e criar nossas tarefas. Edite seu arquivo app.html para parecer com o seguinte:
<template> <h1>${heading}</h1> <form submit.trigger="addTodo()"> <input type="text" value.bind="todoDescription"> <button type="submit">Adicionar Tarefa</button> </form> </template>
Agora temos um form para nossa View. Estamos usando ele para coletar o nome da tarefa digitada pelo usuário. Dê uma olhada no nosso input. Por adicionar .bind ao nosso atributo value, dissemos ao Aurelia que queremos que esse componente esteja ligado à propriedade todoDescription que encontra-se na nossa View-Model. Com o Aurelia nós podemos conectar (fazer um bind) qualquer atributo HTML com sua View-Model através de uma simples expressão de propriedade como essa, apenas adicionando um .bind à propriedade.
Aqui nós temos outra convenção que é importante destacarmos. Quando usamos .bind, o Aurelia age em nosso benefício para pegar o mais sensível “modo de ligação” baseado no elemento e atributo que estamos conectando. Por exemplo, já que esse elemento é do tipo input e que estamos ligando o atributo value desse elemento, então .bind fará com que o Aurelia entenda e sete esse elemento como um elemento de mão dupla (two-way binding). Isso quer dizer que a qualquer momento que o atributo todoDescription em nossa View-Model for alterado, ele também será alterado na propriedade value do nosso elemento input. Além disso, toda vez que nossa propriedade value do nosso elemento input também for alterada, nosso atributo todoDescription em nossa View-Model também será atualizado! Legal, não?
Há algo importante para destacar sobre essa notação. Nós podemos não somente conectar (bind) propriedades mas também anexar eventos. Veja o próprio elemento <form> no código acima. Com Aurelia você pode pegar qualquer evento DOM e adicionar um .trigger a ele. Isso significa que, quando um elemento é disparado, ele pegará (trigger) a expressão associada para ser verificada. Nesse caso, o evento submit dispara a invocação do método addTodo(). Por termos usado o evento submit, isso significa que nossa tarefa será adicionada quer por clicarmos no botão Enter ainda dentro do campo de texto quer por clicarmos no botão “Adicionar Tarefa”.
COMANDOS DE LIGAÇÃO OU CONEXÃO. Por padrão, Aurelia utilizará comandos de ligação de mão dupla (two-way binding) para qualquer ligação utilizada dentro dos forms (formulários) e utilizará ligações de mão única (one-way) para tudo o mais. No entanto, você sempre poderá sobrescrever esse padrão por usar um método de ligação explícito. Por exemplo, ao invés de usar .bind você pode usar .one-way, .two-way ou ainda on-time. De maneira similar, você poderá usar .delegate para a chamada de eventos no lugar de .trigger.
Se você rodar o app agora, você deverá ver algo parecido com isso:
Tente digitar dentro do campo de texto e adicionar uma tarefa. Você deverá notar que o campo é limpo toda vez que você adiciona uma tarefa. A razão para isso é que o atributo value do elemento input tem uma conexão do tipo two-way (mão dupla) que, como vimos, é utilizado por default quando se trata de campos de formulário. Sendo assim ao clicar em Adicionar Tarefa, nosso código limpa o atributo todoDescription em nossa View-Model. Só para referência, segue o nosso método addTodo criado na parte 2 desse tutorial…
addTodo(){ if(this.todoDescription){ this.todos.push(new Todo(this.todoDescription)); this.todoDescription = ""; } }
Visualizando as tarefas
Bem… podemos adicionar as tarefas, mas ainda não podemos vê-las. Vamos consertar isso por ver como o Aurelia trata listas de dados. Vá no seu arquivo app.html e modifique-o para parecer com o seguinte:
<template> <h1>${heading}</h1> <form submit.trigger="addTodo()"> <input type="text" value.bind="todoDescription"> <button type="submit">Adicionar Tarefa</button> </form> <ul> <li repeat.for="todo of todos"> <input type="checkbox" checked.bind="todo.done"> <span> ${todo.description} </span> <button click.trigger="removeTodo(todo)">Remover</button> </li> </ul> </template>
Para gerar código HTML baseado em um Array, Map ou Set, usamos a sintaxe repeat.for=”local of collection”. Essa sintaxe é baseada na sintaxe for…of do próprio TypeScript. Como você pode ver acima, queremos gerar uma lista com todas as tarefas. Para gerar listas em HTML, usamos a tag <ul></ul> e dentro delas repetimos as tags <li></li> para cada item da lista. Sendo assim, colocamos o atributo repeat.for na tag que queremos repetir, ou seja, <li>. Daí, especificamos que cada item da coleção todos seja atribuído a uma variável chamada todo. Isso é exatamente o que um foreach faz em linguagens como PHP, por exemplo. Através disso, podemos fazer uma conexão (bind) com qualquer propriedade de nossa instância todo. Você está vendo como estamos somente aplicando novamente as mesmas técnicas que antes? Estamos conectando o atributo checked à propriedade done e sua propriedade description está sendo injetada dentro do conteúdo da tag <span>.
Finalmente, estamos adicionando um trigger ao evento click do nosso botão de maneira que possamos remover nossa tarefa. Veja que o método removeTodo ainda está no escopo. Tal como no TypeScript, dentro de um loop, você ainda tem acesso à variável do bloco de fora. Isso nos permite chamar o método removeTodo da classe App, passando uma instância Todo específica para que possamos removê-la.
Rode novamente sua aplicação ($ http-server -o -c-1) e você verá algo como abaixo.
Quase acabando… Há uma coisa que está faltando: riscar as tarefas completas quando marcamos o checkbox. Vamos fazer uma pequena modificação de nossa view…
<template> <h1>${heading}</h1> <form submit.trigger="addTodo()"> <input type="text" value.bind="todoDescription"> <button type="submit">Adicionar Tarefa</button> </form> <ul> <li repeat.for="todo of todos"> <input type="checkbox" checked.bind="todo.done"> <span css="text-decoration: ${todo.done ? 'line-through' : 'none'}"> ${todo.description} </span> <button click.trigger="removeTodo(todo)">Remover</button> </li> </ul> </template>
Esse exemplo final mostra como podemos conectar código CSS diretamente em um elemento HTML, nesse caso o <span>. Também mostra como podemos usar a sintaxe ${} diretamente dentro de qualquer atributo. Nesse caso, queremos adicionar o text-decoration do line-through sempre que a propriedade done da tarefa for true. Se não for true, queremos que o valor seja none.
ATRIBUTO STYLE VS ATRIBUTO CSS. Use o alias style. Use css quando estiver fazendo a interpolação de strings para se certificar que sua aplicação seja compatível com o IE e o Edge… claro, se você quiser dar suporte para esses navegadores.
Rode mais uma vez a aplicação no servidor ($ http-server -o -c-1) e você deverá ver algo como o abaixo:
Conclusão
Com esse forte foco na experiência do desenvolvedor, Aurelia pode lhe ser útil não somente ao criar aplicações incríveis mas também tornar o processo mais prazeroso e fluído. Os desenvolvedores do Aurelia criaram ele pensando em convenções simples de maneira que você não precise perder tempo com toneladas de configurações ou escrever montanhas de códigos só para se ajustar a um framework teimoso ou restritivo. Você não baterá em um obstáculo com Aurelia. Ele foi cuidadosamente projetado para ser plugável e customizável. Na maior parte do seu tempo você somente escreverá código JavaScript e esquecerá que o framework está lá.
Muito obrigado por ler até aqui esse tutorial de três partes. Deu trabalho traduzir o tutorial bem-documentado do site Aurelia.io. Lá você poderá encontrar outro tutorial, que é o de um Gerenciador de Contatos e aprender a como setar um projeto Aurelia do zero, usando o Aurelia CLI. Gostou do tutorial e gostaria de ver outros tutoriais em português usando Aurelia? Deixe um comentário abaixo. Forte abraço!
______
* Se você não tiver o NodeJS instalado, poderá instalá-lo através do seguinte link: https://nodejs.org/en/. Escolha a opção que você achar melhor. Instalando o NodeJS ele já virá com o gerenciador de pacotes NPM.
Pingback: Tutorial Aurelia JS - Todo List | WillBlog
Pingback: Tutorial Aurelia JS: criando um Todo List, parte 2 de 3 | WillBlog