Curso de Javascript Completo do iniciante ao mestre - Parte 2

Seção 22 - Design Pattern: MVC

Aula 273 - Apresentação do projeto

O projeto foi construido com o framework Materialize e com um pequeno código CSS sem maiores detalhes.
O HTML tem uma estrutura básica com um <input>, e um <button> e uma tabela cujos dados serão trabalhados posteriormente.
Ao final um script com um array de objetos que serão tratados no decorrer do projeto.
Funções de cálculo e média vide Aula 99 e seguintes.

Aula 274 - Calcular média

Nesta aula criamos a rotina para recuperação de dados e cálculo das médias. Para criar as médias percorremos os dados do array de alunos com o método forEach() e criamos um novo atributo média para o array. Em seguida criamos um loop for...in no objeto notas de cada aluno recuperando o nome do atributo e o valor de cada nota. Os valores são passados com o spread operator como parâmetro e tratados pela função avarege() e atribuidos como atributo / valor no objeto média. Esses dados serão enviados para as tabelas do HTML portanto os valores fixos do <thead> e <tbody> foram apagados.

Aula 275 - Escrever tag thead

Para a inclusão dos dados no thead fiz um resolução um pouco diferente ddo professor. Na minha resolução criei um array de materias recuperando os valores diretamente na rotina de criação das médias e utilizei um indexOf() para evitar que fossem incluidas matérias repetidas por ter mais de um aluno. Com esse array montado, fiz a inclusão dos valores nas <td> através de um forEach().
Na resolução do professor ele utilizou o método Object.keys(alunos[0]).notas).map(), ou seja, ele recuperou os valores das chaves do objeto notas no array alunos e fez um map() de cada elemento para criar as <td> com as matérias.
Essa abordagem é interessante para utilizar os conceitos aprendidos em objetos, porém tem a desvantagem de utilizar especificamente as matérias do aluno no índice '0'. Caso outros alunos tenham matérias diferentes em sua grade elas não serão listadas na tabela.
Uma vantagem da execução do professor é que ele utilizaou o método join() para criar uma única linha com todos os <td> e inserí-los de uma só vez no html, o que diminui a quantidade de maipulações do DOM. Na minha resolução fiz uma manipulação para cada passo do loop forEach()

Aula 276 - Escrever tbody

Nesta aula fizemos o lançamento das médias na tabela. Para a obtenção do nome do aluno fiz da mesma forma que o professor. Já para a obtenção da média utilizei o método map() assim as notas devem estar na mesma ordem que as notas que foram lançadas no array, ou seja, todos os objetos de média devem estar na mesma sequencia (o que nesse caso acontece).
Na execução do professor ele utilizou o método forEach() percorrendo o objeto notas e recuperando o nome das matérias. Esse nome é passado para recuperar o valor das médias de cada matéria. A consulta para ser testada no console seria a seguinte:
alunos[0].media["ciencias"]
ou seja a busca dos valores é feita pelo nome da matéria independente da ordem em que ela esteja no objeto.

Aula 277 - Adicionar aluno

Em princípio meu erro para executar esse passo está no modo que eu estava recuperando o listener. Estava fazendo o listener no <button> mas como é um <form> está sendo gerado um ?action= na URL. Relembrando precisamos fazer o listener no submit e passar o método preventDefault(). No mais inclui o novo aluno além dos demais dados, inclusive as notas utilizando os métodos estudados defineProperty(). No caso desse método tive alguns problemas para incluir os valores nas propriedades o que consegui resolver alterando as propriedades enumerable e writable.
Quanto a resolução do professor, não houve nenhuma grande diferença da minha, o únnico porém é que ele não gerou os dados da estrutura de dados de forma programática, mas sim inseriu o objeto inteiro de forma rígida apenas alterando o nome do aluno.

Aula 278 - O que é o padrão MVC?

O MVC é um padrão de projeto (design pattern). Seu significado é Model, View , Controller.
O Model é a classe que representa os dados da aplicação. Possui as propriedades do objeto.
A View é a classe que possui os métodos e propriedades para, a partir dos dados, gerar a visualização em tela.
O Controller é a classe que liga os dados (Model) à tela (View). É a classe que orquestra a comunicação entre ambas.
As classes do Model não tem funcionalidade. O Controller liga a View aos Services que é quem trata os dados do Model.

Aula 279 - Models e services

Nesta aula criamos primeiramente os diretórios para trabalhar com o MVC. Note que o VSCode já cria icones especiais para as pastas com nomes no padrão MVC.
Nos diretórios específicos vamos criar os arquivos para cada tipo de operação.
No diretório Models criamos o arquivo que irá conter as classes das estruturas de dados.
No diretório Services criamos os arquivos que serão responsáveis pelas operações executadas com os dados obtidos de Models.
No diretório View criamos o arquivo que fará a comunicação externa do programa.
Por fim o diretório Controller recebe os arquivos que fazem a ligação entre Services e View. Nesse arquivo o constructor() da classe recebe como parametros service e view, ou seja toda a orquestração entre os dados manipulados pelo services e retornado para a view é feita nessa classe.
Iniciamos agora a criação das propriedades das classes, partindo de Model.
Para a classe Model recebemos os parametros nome, _id e notas. Para notas criamos um valor default que é um objeto vazio { }.
Para o id foi criada uma lógica simples criando um novo parametro maxId que inicia em '0'. Para cada novo objeto criado na classe AlunoModel testamos se foi passado um número de id. Caso não tenha sido passado esse valor ele irá recuperar o valor do atributo maxId. Caso exista ele receberá o valor passado no parametro e em todos os casos será verificado se o valor do id recebido é maior que o valor armazenado em maxId. Caso positivo ele substitui o valor de maxId.
Para as notas criamos um parametro que recebe as notas com um spread operator. Não entendi bem o motivo, vou esperar para tentar assimilar.
A última propriedade a ser incluida é a media que recebe um objeto vazio { }. Em seguida incluimos o código de cálculo utilizado anteriormente aproveitando a função avarege(). Atenção para a ordem dos arquivos js no HTML.
Para os Services criamos a propriedade alunos que é um array que irá receber os objetos aluno instanciados a partir do Model. Esses objetos são testados para verificar se são instancia de AlunoModel e caso positivo são includos com o método push()no array.
Para finalizar essa aula instanciamos a classe AlunoService e utilizamos o método forEach() para instanciar cada aluno do array pré-definido alunos no Model
Se pesquisarmos no console o nome alunos vamos recuperar o array pre-definido. Entretanto podemos verificar os alunos chamando o objeto instanciado alunosService. Esse objeto que irá receber todos os alunos criados no AlunoModel

Aula 280 / Aula 281 - View - parte 1 / View - parte 2

Criação da classe View. Essa classe recebe como parametro do constructor a referencia a tag <table>. Instanciamos a classe View no arquivo app.
Essa classe tem como propriedades a table recebida por parametro, as referencias ao <thead> e <tbody> e a propriedade materias que recebe um array com o nomes da matérias.
Criamos uma função(método) para renderizar os dados na tela. Esse método vai receber a mesma sintaxe construida no início do exercício, porém com alguns ajustes das referencias que passarão a utilizar o this (ou seja a referencia da classe) como seletor dos elementos.
Para renderizar as informações dos alunos criou-se uma função render() que recebe como parametro alunos.
Nessa função copiamos a estrutura utilizada no arquivo app. Fiz uma estrutura que recuperava os dados nos parametros, mas o correto é trabalhar com o padrão MVC. Dessa forma a função render apenas trata os dados recebido do Controller.
Então o método render() fica na estrutura de View e recebe os parâmetros do Controller. O Controller por sua vez recebe como parâmetros service e view e executa a função view.render() que recebe como parametro service.alunos.
No arquivo app instanciamos a classe Controller passando como parametro os objetos alunosService e alunosView.

Aula 282 - Adicionar aluno com controller

A separação da rotina de add é feita no app e no controller. No arquivo app vamos manter o listener que monitora o submit, o preventDefault() do submit e a recuperação do valor digitado.
Em seguida enviamos o valor recebido no <input> para o objeto alunosController atravé do método add() que recebe como parametro o nome. Note que o professor utilizou como variável a própria palavra nome portanto não precisou passar o conjunto chave: valor poiss os dois tem o mesmo valor (nome: nome = nome). Eu utilizei como valor _name portanto tive que passar o par nome: _name.
No controller criamos o método add() que recebe aluno como parametro e executa o método add() de services e o método render() de view.
Para cada alunos criado incluimos o nome. Nesse momento as notas e a média são incluidas como um objeto vazio pela classe AlunoModel (notas é passado como parametro default e média é um atributo que tem como valor um objeto vazio padrão). Já o _id passa pela lógica generateId.
Para fazer a inclusão das notas criamos no render() do view om operador ternário no loop forEach() que le os valores das notas. Esse ternário faz o teste para verificar se as notas são undefined. Caso seja cria um link para a página de inclusão de notas (a ser desenvolvida).
Para finalizar foi criada uma lógica para verificar sse existe alguma nota no objeto notas. Caso não exista cria apenas um link para adicionar todas as notas.

Aula 283 / Aula 284 - HTML para edição de aluno / Obter aluno por id

Inclusão do arquivo HTML para a incluão de notas e explicação de sua forma.
Note que alguns dos módulos JS não são necessários nessa página (View, Controller) pois contém classes específicas para a página principal, como criação da tabela.
O objeto fixo alunos foi transferido para a página de edit, bem como a instacia do objeto alunosService mas apenas de forma provisória pois esses dados vão causar problemas. Outra coisa que precisamos fazer é tratar o id do aluno que recuperamos na URL.
Para recuperar o valor pasado no URL utilizamos a propriedade window.location.search que retorna o valor a partir do '?'.
Para recuperar apena o valor instanciamos o método URLSearchParams(parametro_da_URL) const URLParams = new URLSearchParams(parametro_da_URL);
console.log(URLParams.get('nome_do_parametro'));

Feito isso criamos um método em search para fazer o filtro dos alunos pelo id. Para isso utilizamos o método find() no array de objetos alunos.
O valor recuperado no get() deve ser convertido para inteiro. Com isso conseguimos recuperar o aluno individualmente.

Aula 285 a 287 - Salvar dados no localStorage / obter dado do localStorage / Usar apenas uma única fonte de dados (localStorage)

Primeiramente criamo um botão Cancelar para o formulário de edição que retorna para a página principal.
Em seguida vamos utilizar o JSON.stringify() para converter os dados do objeto em string para armazená-lo no localStorage.
O método para inclusão de dados no localStorage poderia ser criado no Controller mas o mais apropriado é no Services pois é onde é processado o método add(). Desse modo após ser incluido no array chamamos o método que inclui os dados no localStorage. Esse método converte os dados em uma string JSON e inclui os dados com o método localStorage.setItem(nome_da_chave_armazenamento, dados_a_armazenar).
Ainda em Services criamos um novo método para verificar se existem dados no localStorage, e caso positivo renderiza-los na tela.
Esse método substitui a rotina que importava os dados fixos do arquivo app. Primeiramente recuperamos os dados com o método localStorage.getItem(nome_da_chave_armazenamento). Em seguida fazemos o teste para verificar se há dados e caso positivo convertemos os dados com o JSON.parse() e executamos o loop forEach() para criar os objetos de cada aluno.
Por fim removemos os dados fixos do arquivo edit e passamos a recuperar os dados dos alunos pelo id e apresentá-los na tela.

Aula 288 - Única fonte de dados para matérias

Nesse ponto vamos escolher qual abordagem utilizar para a lista de matérias. Entre as opções a que mais me interessou foi criar um Model com as informações de matérias. A desvantagem é que não poderemos manipular os dados sem a criação de serviços e outras estruturas de controle. Mesmo assim acho que seria a abordagem mais profissional.
A abordagem utilizada entretanto será a de criar um Service que armazene os dados das matérias, uma vez que a única informação necessária é a string com o nome da matéria.
Criamos então um novo Service para materias. Esse Service tem apenas o array de matérias. Criei um método add para incluir matérias no array. Não vou nesse momento desenvolver essa idéia, mas pelo menos tenho como trabalhar nisso depois (vamos ver como desenrrola a aula).
Para trabalhar com essa classe temos duas opções. Instanciar um objeto matéria como um novo objeto ou intanciar as matérias diretamente na View junto com a instancia de AlunosView. Com isso passamos as matérias como parametro para o constructor() de AlunosView substituindo o valor fixo pelo parametro recebido. Como materias não foi instanciado acredito que não seja possível adicionar matérias nesse modo.

Aula 289 a 292 - editAlunoView / editAlunoController / Utilizar MateriasService em EditAlunoView

Nesta aula criamos um arquivo para gerenciar o campo de inclusão de notas. Além de alguns ajustes no HTML tranferimos as tags que criam os campos de entrada dos dados das notas para o arquivo de View criado de forma que as linhas sejam adicionadas na port de edição de acordo como as notas a serem incluidas.
O constructor() da View do edit vai receber como parametros o container dos campos a serem editados e a lista de matérias recuperada do Services de matérias. Instaciamos essa classe no script do arquivo edit.html
Em seguida criamos o arquivo Controller do edit que recebe como parametros o model que é o aluno a ser editado e o objeto instanciado da classe View que será renderizado no Controller.
Na sequencia criamos o parametro materias na View e utilizamos o método map() para recuperar todas as matérias e retornar uma linha de entrada de dados para cada uma.
Por fim incluimos os nomes das matérias no value do primeiro <input> da estrutura HTML e tornamos ela disabled para que não se edite seus valores.

Aula 293 - Refactor de EditView

Aqui vamos alterar a abrangencia do EditAluno para que possamos também recuperar na View os dados do aluno para que possam ser editados. Para isso criamos uma nova propriedade na tag <form> para que ela faça parte dos campos que são passados como parametro para a View.
Ainda no arquivo edit.html incluimos um listener para o botão de salvar que vai recuperar os dados do campo nome para possibilitar a edição do nome do aluno e vai executar o método edit() em editAlunoController, passando como parametro aluno e nome.
O Controller de EditAluno vai ter o método edit() que irá receber o nome do aluno para edição e terá um objeto notas que irá receber as notas dos alunos e irá chamar o método edit() do Service que futuramente irá tratar o aluno e as notas.

Aula 294 / Aula 295 - Criar objeto notas a partir dos dados do form / Salvar notas em localStorage

Primeiro fizemos alguns ajustes na construção das tags da View para unificar os nomes dos <input> e criamos um atributo na row para selecionar a origem de dados. Em seguida incluimos o mome da matéria nos id das notas e criamos atributos para cada trimestre com valores de 0 a 3.
No Controller criamos um array com todas as matérias de cada linha. Para isso utilizamos o método Array.from() recuperando cada matéria. Nesse array percorremos cada posição com o método forEach() e criamos um novo array para cada matéria para recuperar as notas de cada matéria. Em ambos os casos recuperamos as informações utilizando querySelectorAll() com os atributos criados nas tags.
Em seguida recuperamos os nomes das matérias com getAttribute nos atributos matéria de cada linha. Esses valores são atribuidos ao objeto notas como chave de atributo. Após isso fizemos um map() nos valores dos <input> para criar o array de notas.
A diferença para a minha resolução foi que eu utilizei o forEach() e tive que fazer o push() dos dados no array, ao passo que utilizando o map() o retorno é um array.
Para gravar os valores em LocalStorage atribuimos a propriedade aluno.notas o valor de notas (por algum motivo isso não funcionou para mim).
No Services executamos no método edit() o método updateLocalStorage() para armazenar os dados em LocalStorage, entretanto não é claculada a média. Para resolver isso retiramos do constructor() no Model a rotina que executava o cálculo de média e criamos um método para essa operação que é executada tanto no Model quanto no Service. A próxima tarefa é apresentar na tela de edit() os valores atuais das notas. Se passamos o value diretamente nas tags <input> temos um erro.
Veremos como resolver isso na próxima aula.

Aula 296 / Aula 297 - Encadeamento opcional / Refactor de usabilidade

Encadeamento opcional (optional chaining) faz um teste para verificar se determinado objeto existe ou não em uma cadeia de objetos. Por exemplo caso tenhamos o seguinte objeto:
obj = {foo1: {foo2: {foo3: {foo4: ''}}}}

Para verificar essa estrutura sem receber erros em casos em que queremos verificar se existem objetos poderíamos fazer verificações do tipo:
obj.foo1 && obj.foo1.foo2 && obj.foo1.foo2.foo3...

Já com o encadeamento opcional podemos fazer da seguinte forma:
obj.foo1?.foo2?.foo3?.foo4?.foo5?.foo'n'

Com isso recebemos uma mensagem undefined ao invés de um erro.
Esse procedimento vai ser utilizado na View do edit para evitar que tenhamos erros quando formos editar alunos com os campos de valores vazios e com a propriedade value setada para o valor de notas do array. Isso porque quando passamos os valores e o sistema verifica o array vazio ele retorna um erro. Com esse procedimento ele passa a retornar undefined e permite que acessemos os campos.
Em seguida fazemos alguns ajustes de usabillidade. A primeira delas foi atribuir o método window.location.assign('index.html') no arquivo edit para ao clicar no botão salvar retornar a tela inicial.
Para editar as notas dos alunos após a digitação apenas incluimos um link na tag dor nomes dos alunos referenciando o arquivo de edit e o _id do aluno, com os mesmo link utilizado para incluir as notas.

Aula 298 - Filtrar aluno por nome

Para criar o filtro de nomes inserimos um pequeno código HTML para criar o input do filtro.
Verificamos o conteudo desse filtro no app e testamos se o tamanho do valor digitado é maior que 2 caracteres ou igual a 0. Nesses casos chamaremos um método search() no Controller. Esse método chamará o método searchName() no Service e fará a renderização dos dados na tela com o métod render() da View.
O método searchName() irá executar um filter e procurará com o indexOf() os valores no nome dos alunos.

Aula 300 - Guardar estado em sessionStorage Aula 300 - Código Final refatorado

Diferente do localStorage 0 sessionStorage armazena dados que precisam ser recuperados apenas naquela seção como por exemplo as seleções, filtros e dados digitados pelo usuário durante a seção e apenas nela.
A sintaxe e os métodos são os mesmos dos utilizados no localStorage, passamos uma chave para criar a referencia no sessionStorage e o valor a ser armazenado. Feito isso trabalhamos com os métodos setItem() e getItem().
Criamos o setItem() no listener do evento a ser armazenado, e recuperamos caso exista valor armazenado. Entretanto quando retornamos a página anterior apesar de manter o valor não realizmos novamente o filtro. Para reexecutar esse código criamos um objeto Event() monitorando o mesmo evento que dispara o filtro (no caso o 'input'). Em seguida chamanos o envento que está sendo monitorado e utilizamos o método dispatchEvent() com o objeto de evento criado como parametro. Esse método não é compatível com todas as versões de navegadores. Para executar em modo de compatibilidade podemos utilizar o método createEvent(). Nesse caso devemos iniciar o método com document.createEvent('nome_do_evento') e em seguida inicializar o evento e definir qual evento será monitorado.

Seção 23 - ES Modules

Aula 301 / Aula 302 - Introdução / Sintaxes para trabalhar com módulos

O ES Models surgiu como um modo de facilitar a inclusão de diversos <script src=''> nas aplicações JS. Outro problema é a ordem de execução dos arquivos de script e as variáveis globais.
Dividir uma grande aplicação em pequenos módulos traz vantagens para manutenção (mais fácil), namespacing (isolar escopos de variáveis) e reutilização (criação de módulos reutilizáveis).
No lado do servidor com o NodeJS temos o CommonJS que trabalha com o exports e require para separar os módulos da aplicação. Podemos utilizar a sintaxe do CommonJS, bem como outras (AMD / UMD) através de bundles como o webpack. Já a ESM é nativa para o Front End e utiliza a sintaxe export e import. Essa sintaxe tem suporte no Back End a partir da versão 14 com algumas adaptações.

Aula 303 - ESM na prática

Para criar sintaxes utilizando o ES Moddules, criamos uma arquivo JS principal que irá receber os dados dos demais arquivos. Esse arquivo deve ser invocado no HTML no <script src='' type='module'> com o type modules. Esse arquivo principal receberá as funções dos arquivos de módulos. Os arquivos de módulos utilizarão o operador export para indicar que aquela função pode ser acessada em outros arquivos e os arquivos que puderem executar essa função vão utilizar o operaddor import para receber essa função. Podemos utilizar quando exportamos o arquivo o operador default que vai fazer com que a função exportada possa ser impotada e executada com qualquer nome. Quando exportamos a função sem o default precisamos importa-la com o mesmo nome de exportação declatado entre chaves '{}'. Podemos exportar qualquer tipo de dado e não apenas funções. Podemos exportar vários elementos de uma vez declarando todos entre chaves {}.

Aula 304 - Refatorar Lista de Alunos com ESM

Vamos refatorar o código MVC para ESM. Primeiramente alteramos o arquivo app.js para index.js, e incluimos no <script> o type='module'. Em seguida colocamos o operador export em todas as classes dos arquivos MVC. Em seguida fazemos a importação de todos os arquivos necessários em cada módulo.
O próximo passo é remover o script que estava no arquivo edit.html e criar um arquivo JS com esse script. Por fim fazemos a importação dos módulos necessários no arquivo edit.
Assim quando fazemos a aplicação utilizando o MVC, fica fácil portar ela para o sistema de model.

Requisições assíncronas (AJAX)

Aula 305 / Aula 306 - Introdução / XMLHttpRequest

A sigla AJAX significa Asynchronous Javascript and XML, basicamente é quando precisamos de uma comunicação assíncrona entre cliente e servidor. O termo ainda é aplicado muito embora hoje não se utilize mais o XML mas sim o JSON.
A diferença entre programação sincriona e assincrona consiste em que na primeira o código é executado na ordem em que aparece no arquivo e é bloqueante. Já na assíncrona o código não precisa ser executado na ordem que aparece além de não ser bloqueante.
Já o XML é um tipo de arquivo de tranporte de dados. Ele é estruturado de modo semelhante ao HTML e possui inclusive alguns métodos do DOM.
Já o JSON tem uma estrutura semelhante a um objeto e deve obedecer apenas duas regras: nome de propriedades e strings devem estar entre aspas duplas e não podemos utilizar vírgula após o último elemento.
Falando agora sobre HTTP, ele é um protocolo de comunicação que transporta não apenas HTML mas também JSON, JS, XML, etc.
As comunicações entre cliente e servidor são feitas com request e response.
A comunicação no browser é feita através do XMR que podemos analisar através do DevTools do navegador na aba de Network. Lá podemos verificar todas as informações das comunicações estabelecidas pelo XHR, inclusive o status code que são os códigos de mensagens entre as comunicações. Podemos ver a lista de códigos em Códigos de status de respostas HTTP
O XMLHttpRequest é um objeto que contém métodos para conexão com o servidor. Hoje temos outras maneiras de fazer essa comunicação com async/await, fetch, promises. O XMLHttpRequest possui quatro operações necessárias:
Instaciar objeto, open(), send() e listener onreadystatechange.
O listener de onreadystatechange pode receber como resposta:
0 Conexão não iniciada;
1 request configurada;
2 request enviada;
3 em processamento;
4 resposta recebida (completa: sucesso ou falha).

Aula 307 / Aula 308 - XMLHttpRequest na prática / Tratar erro de requisições

Vamos criar um arquivo JSON para testar as requisições com get. Isso geralmente fazemos isso através de APIs que são aplicações que fazem a ligação entre o frontend e o backend.
Os verbos HTML são GET, POST, PUT, PATCH, DELETE, OPTIONS.
Fizemos um arquivo HTML com um script para fazer uma consulta ao arquivo 'JSON'. Esse script segue a estrutura explicada na aula anterior. O método open() recebe como parametro o tipo de operação HTML e a URL a ser consultada. O método send() não precisa de parametros e o listener recebe uma função que irá processar as requisições.
No exemplo fizmos um teste lógico para verificar o estado do listener e o status da requisição. Caso os dois sejam positivos (retornaram sem erro) apresentam os dados no console. Os dados retornados em uma XHR são do tipo string portanto para fazermos consultas temos que converte-los para um formato tratável como o JSON. Em cao de erro retornamos o código de erro através do status.

Aula 309 / Aula 310 - Abstrair a complexidade do XMLHttpRequest / Para refletir

Aqui isolamos em um arquivo as funções de requisição de dados. Esse arquivo tem uma função que recebe como parametro o tipo de requisição, a url que contém os dados, um função de callback que irá executar a requisição e item de dados que será parametro do send() caso ele seja necessário.
A função de callback será responsável por tratar os dados recebidos pela resposta ou por processar o erro caso houver.
Alguns logs no console permitem entender como funciona o código assincrono. Os logs são apresentados antes do retorno dos dados por mais que a resposta do servidor seja rápida.

Aula 311 / 312- Todo list com API fake / Conhecendo o Postman

Vamos reescrever o APP da aula 158 ('Todo list') para que ele receba dados através de requisições.
Para isso vamos utilizar uma ferramenta de testes no Web chamada {JSON} Placeholder. Aqui temos diversas listas fake para testar requisições.
Essa ferramenta de testes permite utilizar os verbos GET, POST, PUT, PATCH, DELETE, etc.
Na documentação ela trabalha com o método de requisições fetch que será estudado adiante.
O GET é utilizado para ler os dados da base. Já o POST adiciona novas informações. O PUT e o PATCH alteram os dados, com a diferença que o primeiro exige que se envie todas as informações atualizadas, já o segundo recebe a 'id' pela URL e altera apenas o dado selecionado. Podemos utilizar o DELETE para excluir dados.
Para testar as APIs temos o aplicativo Postman que faz teste das requisições do mesmo modo que o Insomnia. Podemos fazer todos os tipos de requisições e testar o seu retorno. Para testar utilizamos os dados do site {JSON} Placeholder.

Aula 313 / Aula 316 - Task.model.js / Refatoração / Spoiler: trabalhar com JSON local usando o json-server / Extra: corrigindo o CSS

Nesta aula vamos refatorar o projeto, trabalhando com ESM.
A primeira coisa a fazer é inserir o type='module' na chamada do arquivo de script. Em seguida criamos o primeiro arquivo de Model com a função Task() e fizemos a exportação e importação.
Em seguida copiamos o arquivo com os métodos do XMLHttpRequest para nosso projeto. Ele será responsável por recuperar os dados do site {JSON} Placeholder.
Em seguida importamos a função createXMLHttpRequest() para o arquivo principal. Criamos uma função init() que será a função de callback a ser executada após recebermos os dados da requisição, e configuramos os parametros da função de requisição.
Em seguida precisamos fazer alguns ajustes nos nomes dos atributos do Model
Uma outra alteração foi no tratamento do erro de verificação do status da requisição. Alteramos o if de executar caso haja negação do erro para não executar caso haja erro.
Quando adicionamos tarefas trabalhando com requisições precisariamos utilizar o método POST (lembrando que o site que estamos utilizando para as requisições não permite enviar dados). Entretanto no nosso aplicativo estamos simplesmente fazendo um push() para o array de tarefas e renderizando novamente a lista. A API por ser fake encaminha como retorno ao método POST o código 201, entretanto não altera realmente os dados. Para ajustar esse problema vamos utilizar o JSON-server que cria um JSON estático na máquina e permite fazer requisições como se estivessemos tratando um banco de dados.
Fizemos tamném um pequeno tratamento do CSS, substituindo o display: grid por display: flex e mais alguns ajustes entre os elementos.

Aula 317 - introdução ao NPM

Aqui primeiramente verificamos a instalção do node e do npm. Em seguida iniciamos o projeto com o comando:
$ npm init -y
Feito isso já temos um proejeto iniciado. O próximo passo é instalar o json-server Documentação. Para isso vamos utilizar o comando:
$ npm install json-server --save-dev ou $ npm install json-server -D (a flag --save-dev ou -D significa que o pacote só aparecerá no ambiente de desenvolvimento 'devDependencies').
Como fizemos a instalação de pacotes do 'node' criei o arquivo .gitignore e o readme.md.
Em seguida criamos um arquivo db.json para criar uma estrutura de dados fake que será utnilizada no projeto.
Em seguida executamos o json-server com o comando:
npx json-server arquivo.json
Com isso iniciamos um servidor com dois end-points (conforme foi criado no arquivo json). Acessando esses end-points temos uma retorno igual ao que recebemos quando acessamos o {JSON} Placeholder.
Essa estrutura criada permite a consulta dos end-points ccom filtros como por exemplo:
localhost:3000/users/1/tasks
Não entendi como é feita a vinculação dos ids, preciso estudar isso.
Para que o servidor json seja atualizado automaticamente quando alteramos a base de dados devemos incluir a flag --watch dessa forma:
npx json-server --watch arquivo.json.
Podemos automatizar o processo de inicialização do json-server, incluindo o comando de inicialização no arquivo package.json do projeto. Para isso inserimos o comando de inicialização dos serviços que desejamos no atributo "scripts", "start": "módulo_a_executar" .
Uma vez criada essa entrada, basta iniciarmos o projeto com o comando:
$ npm start
Podemos executar o comando não apenas com o atributo start. Podemos criar um nome personalizado para executar o módulo e executá-lo com o comando:
$ npm run nome_personalizado.
Para instalar as dependencias em um projeto que não esteja inicializado podemos iniciar o projeto e instalar as dependencias com o comando:
$ npm install.
Pelo postman vamos agora criar uma nova tarefa com o método POST. Para isso selecionamos no aplicativo o método desejado e inserimos na opção body os dados que desejamos incluir no arquivo JSON. Quando fizemos a inclusão a primeira vez tivemos um erro pois é necessário que as tasks também tenham um id. Criamos esse campo e fizemos o POST de dados com sucesso.

Aula 319 - enviar POST

Para criarmos a rotina de POST vamos refatorar a rotina que tem a função de addTask(). Essa função é iniciada pelo listener do botão submit.
Iremos utilizar a função XMLHttpRequest() utilizando o método POST e passando como parametro a url da API do json, a função que executava o push() dos dados e por fim os dados a serem inseridos.
Os dados não serão mais incluidos diretamente pela função addTasks() mas sim pelo retorno da função de callback do POST.
Em seguida ajustamos as variáveis url para que possamos acessar os usuários de acordo com o valor passado e não de modo fixo. Outro ajuste a ser feito é no método do XMLHttpRequest(). Esse método estava fazendo um teste apenas para os códigos de retorno positivos da API do método GET (200 ou 304). Os códigos de erro das comunicações AJAX são os valores maiores que 400, assim podemos alterar o teste lógico para retornar erro apenas nos casos de código de retorno acima de 400.
Nesse momento ao testar a API verificamos que não estamos gravando os dados corretamente. Isso porque os dados não estão sendo recebidos como json. Para corrigir isso vamos precisar fazer os seguintes passos:
Como estamos trabalhando com um método que tratava 'também' arquivos xml precisamos informar que o tipo de estrutura que estamos enviando é json. Fazemos isso incluindo na função XMLHttpRequest() a identificação do tipo de dados da seguinte forma:
xhr.setRequestHeader('Content-Type', 'application/json;charset=UTF-8').
A próxima alteração é alterar o tipo de dados enviados para uma string ao invés de um objeto. Fazemos isso alterando os dados com JSON.stringify().
Apenas para entender o funcionamento do POST a função de callback do método que faz executa esse método recebe como resposta os dados que foram enviados para o json-server, assim o parametro enviado para a função de callback é o valor recuperado na resposta ou seja response.title.

Aula 320 / Aula 321 - Usar apenas o json-server / Natureza assíncrona Link para inicilaizar o projeto com json-server ativado

Aqui inserimos uma flag no package.json para que o próprio json-server seja responsável por levantar o servidor html. Para isso incluimos no atributo que possui as configurações de inicio do json-server a seguinte flag: --static ./
Essa flag incia o servidor html em localhost:3000. Por padrão ele procura a pasta public e o arquivo index.html. Nesse caso passamos como pasta padrão a pasta do projeto './' e chamamos o arquivo pelo nome no navegador.
Essa alteração foi feita para evitar que tenhamos dois servidores concorrendo no mesmo projeto.
Analisando agora a questão de sincronismo do código, inserimos alguns consoles para entender a ordem de execução da inclusãoo de dados.
Quando acionamos o evento de listener para adicionar uma tarefa chamamos a função addTask(). Essa função executa a função createXMLHttpRequest() que envia o método http POST e chama a função de callback que é responsável por adicionar os dados no array que será apresentado na tela. Essa função finaliza sua execução assim como a função addTask(), entretanto, por ser assíncrona a função de callback só finaliza sua execução após isso. Desse modo a função de renderTasks() que é executada pela função addTask() não faz nada pois os dados ainda não foram inseridos no array.

Aula 322 - Outros métodos HTTP

Os métodos HTTP são os seguintes:
GET: recuperar dados - caminho: '/tasks'
POST: cadastrar dado - caminho: '/tasks'
PUT: atualizar o dado completamente - caminho: '/tasks/:id'
PATCH: atualizar o dado parcialmente - caminho: '/tasks/:id'
DELETE: deletar dado - caminho: '/tasks/:id'
A diferença dos métodos PUT e PATCH são que o primeiro requer se se passe todo o objeto de dados para alteração ao passo que o segundo pode fazer alterações apenas do atributo selecionado.
Uma observação: Toda vez que chamamos o endereço da API na aba de endereços do browser estamos fazendo uma requisição do tipo GET.
Em seguida fizemos algumas dessas operações no Postman.
Quando utilizamos o método PUT com dados incompletos perdemos os dados que não foram alterados, ou seja apagamos todos os dados gravados que não tenham sido declarados no objeto enviado.

Aula 323 / Aula 324 - Problemas no nosso código / Criar serviços para fazer as requisições Link para inicilaizar o projeto com json-server ativado

Entre alguns ajustes de dados que são necessários estão a falta de algumas informações no arquivo JSON que tem no array original.
Outro problema é que estamos fazendo um push() dos dados para o array de objetos o que pode ser substituido pelo GET dos dados armazenados no JSON.
Por fim podemos dividir a aplicação utilizando o padrão MVC.
Criamos o arquivo de Service que passará a ser responsável por fazer as requisições para o banco de dados. Fizemos a importação e exportação dos arquivos necessários. Criamos dois métodos um add e um getTasks (pelo que entendi o método add ainda não está implementado). Em seguida trouxemos as rotinas de GET que estavam no arquivo principal.

Aula 325 - Criar view e controlerLink para inicilaizar o projeto com json-server ativado

Nesta aula vamos criar o Controller que será responsável por processar as requisições do Service e a View que fará a construção da aplicação na tela.
Primeiramente criamos o Conrtroller que irá receber o Service e a View como parametro. O método add do Controller irá executar o método add do Service, já instanciando uma nova Task(note que o VSCode já faz o import do arquivo do Task automaticamente).
A partir daqui ficou complicado acompanhar o desenvolvimento do processo. Essa parte da aula precisarei acompanhar novamente no futuro, mas em resumo criamos o arquivo da View apenas com a função render(), sem implementa-la ainda. Foi feita a rotina de add no módulo de Service que é responsável pelo POST dos dados.
Foram criadas as instancias dos novos elementos no arquivo principal e os ajustes no arquivo de listener.

Aula 326 / Aula 327 - método render() / RefatoraçãoLink para inicilaizar o projeto com json-server ativado

Aqui vamos implementar o método render() na View.
Passamos o conteúdo da função renderTasks() para o método render() da View e passamos como parametro para o construtor da View a variável ul que é a referencia para a tag de inclusão da lista no HTML.
Em seguida movemos todo a rotina de construção do HTML para a View porém sem exportar para outros arquivos, ou seja, sem fazer parte da classe de View, mas apenas como um função dentro do arquivo.
O método add() do Controller recebe o parametro tasks de Service. Acontece que no Service o valor adicionado em tasks é um objeto e precisamos passar os parametros separados para o Model. Para isso fizemos um destructuring dos valores recebidos para que eles virem parametros separados para o Model.
Agora removemos a função renderTasks() pois pela nova sintaxe que estamos utilizando não devemos fazer essa operção no arquivo inicial, e sim no controler.

Aula 328 - Recuperar dados após o POSTLink para inicilaizar o projeto com json-server ativado

Neste ponto os icones de edição e manipulaçoa dos dados inseridos apenas estão mainpulando o array que está na memória do projeto e não o arquivo json da aplicação.
Adicionei o getter/setter no Model que eu não tinha implementado e ajustei esses métodos na função clickedUl().
No Service agora não estamos mais executando o push() dos dados no array. Ao executar o add() de dados o POST passa a executar um função que executa o getTasks e recupera os dados diretamente do json.

Aula 329 a Aula 331 - Deletar a tarefa / Atualizar a tarefa / toogleDone()Link para inicilaizar o projeto com json-server ativado

Primeiramente inserimos o id no Model pois não tinhamos esse parametro quando estavamos utilizando arrays. Em seguida criamos um atributo HTML na criação da tag <li> feita na View que irá armazenar o valor da id.
No método de delete() vamos recuperar o id pelo atributo criado na taga <li>. A seguir criamos em Control o método remove() que irá chamar o método remove() no Service e irá renderizar o resultado novamente.
No Service o método remove() recebe o id da tarefa a ser excluida e executa o método DELETE e chama o método GET para reconstruir a lista atualizada.
Tentei fazer os métodos de edição e update mas não consegui.
Para o método de editar o conteúdo, chamamos no Controler um método update() passando como parametro um objeto com o valor recuperado no campo de edição e o id a ser editado, além do userId.
No Controler recebemos no método update() o objeto enviado e o userId e chamamos o Service.
No Service recebemos o objeto task e enviamos com o PATCH no endereço recuperado pelo id passado no objeto, o objeto task passado pelo JSON.Stringify. Esse objeto será enviado pelo AJAX para alteração dos dados.
A impementação do checked foi mais difícil do que eu pensei. Meu começõ estava certo mas não soube, como na tarefa de edição, como passar o objeto com os dados de edição. O método utilizado para enviar os dados foi o mesmo já criado para edição do título, mas foi criado um novo método no Service para fazer a seleção do item a ser alterado com o find() para filtrar o item a ser editado. Para finalizar adicionamos ao task a data atual para ser enviada para o campo updatedAt.

Aula 332 a 334 - Refatoração / Revisão da arquitetura MVC / Dois callbacksLink para inicilaizar o projeto com json-server ativado

Iniciamos uma refatoração e revisão do código. Primeiro retiramos alguns itens desnecessários do arquivo principal e movemos a função de listener dos clicks para fora da funbção init(). A seguir temos duas chamadas para os arquivos Serice e View que não devem estar no arquivo principal.
Primeiramente criamos uma função getTasks() no Controller que executa o GET através do Service e renderiza os dados na tela através do View. Com isso podemos remover a função init().
O próximo passo é remover a variável userId do arquivo principal. Para isso criamos um arquivo de configuração exportando essa variável para o Controller e removemos todos os userId passados por parametro no arquivo inicial, e recebidos por parametro no Controller. A partir de agora o Controller recebe o userId do arquivo de config e apenas passa o seu valor como parametro. Outra variável que pode ser incluida no arquivo config são as variáveis de URL que passam a ser exportadas e importadas pelo Service.
A outa mudança foi retirar o getter/setter do Model pois não estamos utilizando as variáveis de modo privado. O get eu já não estava utilizando (apenas no botão de cancelar). Já o set estava passando o time de update. Esse atributo foi para o método update() em Service.
A estrutura da aplicação após a refatoração para o modelo MVC passou a funcionar da seguinte forma:
O arquivo principal faz a requisição dos dados ao Controler Este por sua vez chama o Service para que ele recupere os dados através do método GET. Além disso o Service a função reder() como parametro e retorna essa função com os dados para o Controler que pede para o View renderizar os dados e apresentar na saida. Para a função de adicionaro fluxo é basicamente o mesmo, entretanto nesse caso o Service faz a requisição de POST, espera o retorno e faz a requisição GET, agora com os dados atualizados.
Vamos agora ajustar o tratamento de erro das requisições da API. Podemos fazer um teste lógico e apresentar a mensagem de erro em um alert ou em uma página de erro. Ou podemos criar duas funções de callback, uma para quando tivermos uma resposta de sucesso e outra para quando temos um erro. Essas funções são incluidas no Controller em todas as ações que são encaminhadas para o Service, onde são recebidas como parametro e passadas para a API do AJAX para testar a resposta do servidor.

Aula 335 a 337 - Promises GET / Promises POST / Promises DELETE e PATCHLink para inicilaizar o projeto com json-server ativado

O promises facilita a manutenção de sistemas que exigem muitas requisições a servidores, pois reduz a quantidade de callbacks do sistema.
Basicamente uma função promise retorna um objeto do tipo promise que contém uma propriedade que identifica o status da requisição que pode ser pendente, preenchido ou rejeitado. A promise pode executar duas funções, uma função de sucess ou uma função de reject.
Diferente do XMLHttpRequest, na Promise não precisamos passar as funções de callback como parametro, mas sim devemos retornar uma função de sucess ou reject. O resto do código de criação da comunicação com o Front-End é o mesmo (criação dos pontos de acesso para consulta de dados com os métodos de comunicação open, send, etc...).
A função de sucess retorna os dados recebidos e a função de reject retorna um Error.
Com isso quando fazemos a requisição para o servidor só precisamos passar o método da requisição e o endereço, e não mais as funções de retorno. Assim tratamos o retorno da promise com .then() para a resposta com sucesso e com .catch()para o erro.
Para o POST recebemos a primeira promise que é relativa a requisição de inclusão dos dados em seguida aguardamos o processamento da promise de retorno dos dados. Dessa forma temos dois .then() encadeados, cada um aguardando a resposta de uma promise. Fiz as funções de DELETE e PATCH sozinho. Uma coisa que fiz diferente foi que passei como parametro do retorno da promise o userId e a cb no mesmo em .then(), entretanto devemos esperar a primeira promise para depois executar o cb.

Aula 337 - Promises (Refatorado)Link para inicilaizar o projeto com json-server ativado

Refatoração do código com promises.

Aula 338 / 341 - Fetch GET / Tratamento de erros Fetch / Fetch POST / Fetch DELETE e PATCHLink para inicilaizar o projeto com json-server ativado

O método fetch() espera uma promise e portanto também opera com .then() e .catch(), entretanto ele é menos sensível a erros de end-point, ou seja, ele só encaminha um erro quando realmente não alcançar nada. Os dados recebidos pelo .then() contém um atributo ok que caso tenha alcançado os dados retorna true.
Assim os dados, para serem alcançados precisam aguardar duas promises, a primeira é a response do fetch() que deve ser convertida com o método response.json(). A seguir recebemos uma nova promise que irá retornar os dados no formato esperado.
O fetch() tem o método GET como padrão (se passamos só a URL ele executará o método GET) e ele substitui toda a rotina que inicializa a comunicação com o servidor (os métodos open(), setRequestHeader, send()).
Podemos passar a verificação das promises do fetch para o retorno do fetch() e nesse ponto podemos fazer através do .then() o tratamento de erros que não são avaliados pelo .catch().
Desse modo podemos verificar a resposta ok do fetch(), se seu retorno for true enviamos o return da promise, e caso seja false, enviamos uma mensagem de erro.
Para passarmos os métodos HTML para o fetch precisamos configurar os parametros no método através de um objeto. Esse objeto recebe o método e os dados (no caso de inclusão ou alteração de dados) e a configuração de Content-Type no header.
Feito isso o fetch passa a ser funcional para qualquer método.

Aula 342 - async / awaitLink para inicilaizar o projeto com json-server ativado

O async/await permite que trabalhemos com requisições assíncronas como se fossem síncronas.
Quando trabalhamos com promises o código continua a executar independente de a resposta ter chegado ou não. Com o async/await podemos declarar que determinada função é assíncrona (async) e que alguma parte do código deve aguardar a resposta para continuar a execução(await). Assim quando definimos a função assíncrona com o async/await não teremos a promise como resposta pois o código aguradará o retorno da função assíncrona antes de continuar a execução.
O método .finally() pode ser utilizado junto com o fetch() e sempre vai ser executado tanto quanto tiver uma resposta válida ao .then() quanto quando tivermos um erro com o .catch().
Para fazermos o tratamento de erros do async/await podemos utilizar o try/catch.

Aula 345 - Desafio: busca CEP

Consegui fazer o desafio. Existem alguns arquivos que não foram utilizados (como o Model) mas podem ser utilizados futuramente então deixei.

Aula 346 / Aula 347 - Resolução desafio / Resolução desafio - parte 2

A resolução é bem mais simples que a que eu fiz. Primeiramente não foi utilizado o MVC, o que facilitou as comunicações entre as promises. A lógica para monitorar o numero do CEP seguiu o mesmo princípio. As mensagens de erro passaram os valores para o alerta de erro. Os valores recebidos foram recuperados como um objeto antes de serem encaminhados para os inputs na tela.
Em seguida foi feita a alteração para que o código funcionasse com async/await e por ultimo utilizando o try/catch para retornar o erro.

Aula 348 - Introdução a web workers

Por se tratar de um sistema single thread, sempre que trabalhamos com sistemas web emfileiramos todos os processos, inclusive os do próprio navegador que está executando o código. Desse modo todos os processos são concorrentes, e assim o código é bloqueante.
Já o Web Worker roda fora da thread do navegador,e portanto não é bloqueante, sendo executado em paralelo com os demais códigos.
As comunicações nestes casos é feita por messages através de request/response. Por não fazer parte do processo do navegador, não permite a utilização de métodos e eventos do DOM.
Para demonstrar o delay causado pela fila na thread, fizemos um loop while para travar a execução quando apertamos o botão. Com isso podemos peceber que enquanto o sistema está no loop while, todas as denais ações ficam na fila aguardando a execução do loop. Nesses casos em que temos processos que podem congelar a ação do usuário é que devemos utilizar os web workers.
Para criarmos um worker primeiramente devemos instanciar um new Worker(arquivo_worker.js) onde o arquivo_worker.js receberá o código que está parando a aplicação.
No exemplo passamos portanto o código que está parando a aplicação para o worker e tranmitimos mensagens entre o processo principal e o processo executado pelo worker para demonstrar a sua ação.

Aula 303 - ESM na prática