AngularJS vs. jQuery
AngularJS e jQuery adotam ideologias muito diferentes. Se você vem do jQuery, pode achar algumas das diferenças surpreendentes. Angular pode deixar você com raiva.
Isso é normal, você deve avançar. Angular vale a pena.
A grande diferença (TLDR)
O jQuery fornece um kit de ferramentas para selecionar bits arbitrários do DOM e fazer alterações ad-hoc neles. Você pode fazer praticamente qualquer coisa que desejar, peça por peça.
O AngularJS fornece um compilador .
O que isso significa é que o AngularJS lê todo o DOM de cima para baixo e o trata como código, literalmente como instruções para o compilador. À medida que atravessa o DOM, ele procura diretivas específicas ( diretivas do compilador) que informam ao compilador AngularJS como se comportar e o que fazer. As diretivas são pequenos objetos cheios de JavaScript que podem ser comparados com atributos, tags, classes ou mesmo comentários.
Quando o compilador Angular determina que uma parte do DOM corresponde a uma diretiva específica, ela chama a função diretiva, passando o elemento DOM, quaisquer atributos, o escopo $ atual (que é um armazenamento de variável local) e alguns outros bits úteis. Esses atributos podem conter expressões que podem ser interpretadas pela diretiva e que informam como renderizar e quando deve ser redesenhado.
As diretivas podem, por sua vez, extrair componentes angulares adicionais, como controladores, serviços etc. O que sai da parte inferior do compilador é um aplicativo da Web totalmente formado, conectado e pronto para uso.
Isso significa que Angular é acionado por modelo . Seu modelo direciona o JavaScript, e não o contrário. Essa é uma inversão radical de papéis, e o completo oposto do JavaScript discreto que escrevemos nos últimos 10 anos. Isso pode levar algum tempo para se acostumar.
Se isso parecer excessivamente prescritivo e limitador, nada poderá estar mais longe da verdade. Como o AngularJS trata seu HTML como código, você obtém granularidade no nível HTML em seu aplicativo da web . Tudo é possível, e a maioria das coisas é surpreendentemente fácil quando você dá alguns saltos conceituais.
Vamos ao âmago da questão.
Primeiro, Angular não substitui o jQuery
Angular e jQuery fazem coisas diferentes. O AngularJS fornece um conjunto de ferramentas para produzir aplicativos da web. O jQuery fornece principalmente ferramentas para modificar o DOM. Se o jQuery estiver presente na sua página, o AngularJS o usará automaticamente. Caso contrário, o AngularJS é enviado com o jQuery Lite, que é uma versão reduzida, mas ainda perfeitamente utilizável do jQuery.
Misko gosta de jQuery e não se opõe a você. No entanto, você descobrirá que, à medida que avança, pode realizar praticamente todo o seu trabalho usando uma combinação de escopo, modelos e diretivas, e deve preferir esse fluxo de trabalho sempre que possível, pois seu código será mais discreto, mais configurável e mais Angular.
Se você usa o jQuery, não deve espalhá-lo por todo o lado. O local correto para manipulação do DOM no AngularJS está em uma diretiva. Mais sobre isso mais tarde.
JavaScript discreto com seletores x modelos declarativos
O jQuery normalmente é aplicado de maneira discreta. Seu código JavaScript está vinculado no cabeçalho (ou no rodapé) e este é o único local em que é mencionado. Usamos seletores para selecionar partes da página e escrever plugins para modificar essas partes.
O JavaScript está no controle. O HTML tem uma existência completamente independente. Seu HTML permanece semântico mesmo sem JavaScript. Os atributos Onclick são uma prática muito ruim.
Uma das primeiras coisas que você notará sobre o AngularJS é que os atributos personalizados estão em toda parte . Seu HTML será repleto de atributos ng, que são essencialmente atributos onClick em esteróides. Essas são diretivas (diretivas do compilador) e são uma das principais maneiras pelas quais o modelo está conectado ao modelo.
Quando você vê isso pela primeira vez, pode se sentir tentado a escrever o AngularJS como JavaScript intrusivo da velha escola (como eu fiz no começo). De fato, o AngularJS não cumpre essas regras. No AngularJS, seu HTML5 é um modelo. É compilado pelo AngularJS para produzir sua página da web.
Esta é a primeira grande diferença. Para o jQuery, sua página da web é um DOM a ser manipulado. Para o AngularJS, seu HTML é um código a ser compilado. O AngularJS lê toda a sua página da Web e literalmente a compila em uma nova página da Web usando seu compilador incorporado.
Seu modelo deve ser declarativo; seu significado deve ficar claro simplesmente lendo-o. Usamos atributos personalizados com nomes significativos. Criamos novos elementos HTML, novamente com nomes significativos. Um designer com conhecimento mínimo em HTML e nenhuma habilidade de codificação pode ler seu modelo AngularJS e entender o que está fazendo. Ele ou ela pode fazer modificações. Este é o caminho angular.
O modelo está no banco do motorista.
Uma das primeiras perguntas que fiz a mim mesmo ao iniciar o AngularJS e executar os tutoriais é "Onde está o meu código?" . Não escrevi JavaScript e, no entanto, tenho todo esse comportamento. A resposta é óbvia. Como o AngularJS compila o DOM, o AngularJS está tratando seu HTML como código. Em muitos casos simples, geralmente basta escrever um modelo e permitir que o AngularJS o compile em um aplicativo para você.
Seu modelo direciona seu aplicativo. É tratado como um DSL . Você escreve componentes AngularJS, e o AngularJS se encarrega de puxá-los e disponibilizá-los no momento certo, com base na estrutura do seu modelo. Isso é muito diferente de um padrão MVC padrão, onde o modelo é apenas para saída.
É mais semelhante ao XSLT do que o Ruby on Rails, por exemplo.
Esta é uma inversão radical de controle que leva algum tempo para se acostumar.
Pare de tentar direcionar seu aplicativo a partir do JavaScript. Deixe o modelo dirigir o aplicativo e o AngularJS cuide da conexão dos componentes. Este também é o caminho angular.
Modelos semânticos vs. modelos semânticos
Com o jQuery, sua página HTML deve conter conteúdo semântico significativo. Se o JavaScript estiver desativado (por um usuário ou mecanismo de pesquisa), seu conteúdo permanecerá acessível.
Porque o AngularJS trata sua página HTML como um modelo. O modelo não deve ser semântico, pois seu conteúdo é normalmente armazenado em seu modelo, que em última análise vem da sua API. O AngularJS compila seu DOM com o modelo para produzir uma página da web semântica.
Sua fonte HTML não é mais semântica; em vez disso, sua API e o DOM compilado são semânticos.
No AngularJS, o significado está no modelo, o HTML é apenas um modelo, apenas para exibição.
Nesse ponto, você provavelmente tem todo tipo de perguntas sobre SEO e acessibilidade, e com razão. Existem questões em aberto aqui. A maioria dos leitores de tela agora analisará o JavaScript. Os mecanismos de pesquisa também podem indexar o conteúdo AJAX . No entanto, convém garantir que você esteja usando URLs pushstate e tenha um mapa do site decente. Veja aqui uma discussão sobre o problema: https://stackoverflow.com/a/23245379/687677
Separação de preocupações (SOC) vs. MVC
A separação de preocupações (SOC) é um padrão que cresceu ao longo de muitos anos de desenvolvimento da web por vários motivos, incluindo SEO, acessibilidade e incompatibilidade do navegador. Se parece com isso:
- HTML - significado semântico. O HTML deve estar sozinho.
- CSS - Estilo, sem o CSS, a página ainda pode ser lida.
- JavaScript - Comportamento, sem o script, o conteúdo permanece.
Novamente, o AngularJS não segue suas regras. Em um golpe, o AngularJS acaba com uma década de sabedoria recebida e implementa um padrão MVC no qual o modelo não é mais semântico, nem um pouco.
Se parece com isso:
- Modelo - seus modelos contêm seus dados semânticos. Modelos são geralmente objetos JSON . Os modelos existem como atributos de um objeto chamado $ scope. Você também pode armazenar funções úteis no $ scope, que seus modelos podem acessar.
- Ver - Suas visualizações são escritas em HTML. A visualização geralmente não é semântica porque seus dados residem no modelo.
- Controlador - Seu controlador é uma função JavaScript que conecta a visualização ao modelo. Sua função é inicializar $ scope. Dependendo do seu aplicativo, você pode ou não precisar criar um controlador. Você pode ter muitos controladores em uma página.
MVC e SOC não estão em extremos opostos da mesma escala, eles estão em eixos completamente diferentes. O SOC não faz sentido em um contexto do AngularJS. Você tem que esquecer e seguir em frente.
Se, como eu, você viveu a guerra dos navegadores, pode achar essa ideia bastante ofensiva. Supere isso, valerá a pena, eu prometo.
Plugins vs. Diretivas
Os plug-ins estendem o jQuery. As Diretivas AngularJS ampliam os recursos do seu navegador.
No jQuery, definimos plugins adicionando funções ao jQuery.prototype. Em seguida, os conectamos ao DOM selecionando elementos e chamando o plug-in no resultado. A idéia é ampliar os recursos do jQuery.
Por exemplo, se você deseja um carrossel em sua página, pode definir uma lista não ordenada de figuras, talvez agrupada em um elemento nav. Você pode escrever um jQuery para selecionar a lista na página e reestilizá-la como uma galeria com tempos limite para executar a animação deslizante.
No AngularJS, definimos diretivas. Uma diretiva é uma função que retorna um objeto JSON. Este objeto informa ao AngularJS quais elementos do DOM procurar e quais alterações fazer neles. As diretivas são conectadas ao modelo usando atributos ou elementos que você inventa. A idéia é estender os recursos do HTML com novos atributos e elementos.
A maneira AngularJS é estender os recursos do HTML com aparência nativa. Você deve escrever HTML parecido com HTML, estendido com atributos e elementos personalizados.
Se você deseja um carrossel, basta usar um <carousel />
elemento, em seguida, defina uma diretiva para inserir um modelo e faça esse otário funcionar.
Muitas diretivas pequenas x plugins grandes com comutadores de configuração
A tendência com o jQuery é escrever grandes plugins como o lightbox que, em seguida, configuramos passando vários valores e opções.
Este é um erro no AngularJS.
Veja o exemplo de uma lista suspensa. Ao escrever um plug-in suspenso, você pode ser tentado a codificar em manipuladores de cliques, talvez uma função para adicionar uma divisa que está para cima ou para baixo, talvez mude a classe do elemento desdobrado, mostre o menu oculto, todas as coisas úteis.
Até que você queira fazer uma pequena alteração.
Digamos que você tenha um menu que deseja desdobrar ao passar o mouse. Bem, agora temos um problema. Nosso plug-in foi conectado ao nosso manipulador de cliques para nós, precisaremos adicionar uma opção de configuração para que ele se comporte de maneira diferente nesse caso específico.
No AngularJS, escrevemos diretivas menores. Nossa diretiva suspensa seria ridiculamente pequena. Pode manter o estado dobrado e fornecer métodos para dobrar (), desdobrar () ou alternar (). Esses métodos simplesmente atualizariam $ scope.menu.visible, que é um booleano que contém o estado.
Agora, em nosso modelo , podemos conectar isso:
<a ng-click="toggle()">Menu</a>
<ul ng-show="menu.visible">
...
</ul>
Precisa atualizar sobre o mouseover?
<a ng-mouseenter="unfold()" ng-mouseleave="fold()">Menu</a>
<ul ng-show="menu.visible">
...
</ul>
O modelo direciona o aplicativo para obter granularidade no nível HTML. Se queremos criar exceções caso a caso, o modelo facilita isso.
Encerramento vs. $ escopo
Os plugins JQuery são criados em um fechamento. A privacidade é mantida dentro desse fechamento. Cabe a você manter sua cadeia de escopo dentro desse fechamento. Você realmente só tem acesso ao conjunto de nós DOM transmitidos ao plugin pelo jQuery, além de quaisquer variáveis locais definidas no fechamento e quaisquer globais que você definiu. Isso significa que os plugins são bastante independentes. Isso é bom, mas pode ser restritivo ao criar um aplicativo inteiro. Tentar passar dados entre seções de uma página dinâmica se torna uma tarefa árdua.
AngularJS possui objetos $ scope. Esses são objetos especiais criados e mantidos pelo AngularJS nos quais você armazena seu modelo. Certas diretivas geram um novo escopo $, que por padrão herda de seu escopo $ empacotado usando herança prototípica JavaScript. O objeto $ scope está acessível no controlador e na visualização.
Esta é a parte inteligente. Como a estrutura da herança $ scope segue aproximadamente a estrutura do DOM, os elementos têm acesso ao seu próprio escopo e a qualquer escopo que contenha perfeitamente, até o escopo global $ (que não é o mesmo que o escopo global).
Isso facilita muito a transmissão de dados e o armazenamento em um nível apropriado. Se um menu suspenso for desdobrado, apenas o escopo $ do menu suspenso precisará saber sobre ele. Se o usuário atualizar suas preferências, convém atualizar o escopo $ global, e quaisquer escopos aninhados que atendam às preferências do usuário serão alertados automaticamente.
Isso pode parecer complicado, de fato, uma vez que você relaxa, é como voar. Você não precisa criar o objeto $ scope, o AngularJS o instancia e configura para você, correta e adequadamente, com base na sua hierarquia de modelos. O AngularJS então o torna disponível para o seu componente usando a mágica da injeção de dependência (mais sobre isso mais adiante).
Alterações manuais do DOM vs. vinculação de dados
No jQuery, você faz todas as alterações do DOM manualmente. Você constrói novos elementos DOM programaticamente. Se você possui uma matriz JSON e deseja colocá-la no DOM, deve escrever uma função para gerar o HTML e inseri-lo.
No AngularJS, você também pode fazer isso, mas é incentivado a usar a ligação de dados. Altere seu modelo e, como o DOM está vinculado a ele por meio de um modelo, o DOM será atualizado automaticamente, sem necessidade de intervenção.
Como a ligação de dados é feita a partir do modelo, usando um atributo ou a sintaxe de chaves, é super fácil de fazer. Há pouca sobrecarga cognitiva associada a isso, então você se encontrará fazendo isso o tempo todo.
<input ng-model="user.name" />
Vincula o elemento de entrada a $scope.user.name
. A atualização da entrada atualizará o valor no seu escopo atual e vice-versa.
Da mesma forma:
<p>
{{user.name}}
</p>
produzirá o nome de usuário em um parágrafo. É uma ligação ativa, portanto, se o $scope.user.name
valor for atualizado, o modelo também será atualizado.
Ajax o tempo todo
No jQuery, fazer uma chamada Ajax é bastante simples, mas ainda é algo em que você pode pensar duas vezes. Há uma complexidade adicional para se pensar e um bom pedaço de script para manter.
No AngularJS, o Ajax é sua solução padrão e acontece o tempo todo, quase sem você perceber. Você pode incluir modelos com ng-include. Você pode aplicar um modelo com a diretiva personalizada mais simples. Você pode encerrar uma chamada Ajax em um serviço e criar um serviço GitHub , ou um serviço Flickr , que você pode acessar com uma facilidade surpreendente.
Objetos de serviço x funções auxiliares
No jQuery, se queremos realizar uma pequena tarefa não relacionada ao domínio, como extrair um feed de uma API, podemos escrever uma pequena função para fazer isso em nosso encerramento. Essa é uma solução válida, mas e se quisermos acessar esse feed com frequência? E se quisermos reutilizar esse código em outro aplicativo?
AngularJS nos fornece objetos de serviço.
Serviços são objetos simples que contêm funções e dados. Eles são sempre singletons, o que significa que nunca pode haver mais de um deles. Digamos que desejamos acessar a API Stack Overflow, podemos escrever um StackOverflowService
que defina métodos para isso.
Digamos que temos um carrinho de compras. Podemos definir um ShoppingCartService que mantém nosso carrinho e contém métodos para adicionar e remover itens. Como o serviço é um singleton e é compartilhado por todos os outros componentes, qualquer objeto que precise pode gravar no carrinho de compras e extrair dados dele. É sempre o mesmo carrinho.
Objetos de serviço são componentes independentes do AngularJS que podemos usar e reutilizar como acharmos melhor. Eles são objetos JSON simples que contêm funções e dados. Eles sempre são singletons; portanto, se você armazenar dados em um serviço em um local, poderá obtê-los em outro lugar apenas solicitando o mesmo serviço.
Injeção de Dependência (DI) vs. Instatiação - aka des-spaghettification
O AngularJS gerencia suas dependências para você. Se você deseja um objeto, basta consultá-lo e o AngularJS o obterá para você.
Até você começar a usar isso, é difícil explicar o quanto esse benefício é massivo. Nada como o AngularJS DI existe dentro do jQuery.
DI significa que, em vez de escrever seu aplicativo e conectá-lo, você define uma biblioteca de componentes, cada um identificado por uma sequência.
Digamos que eu tenha um componente chamado 'FlickrService', que define métodos para obter feeds JSON do Flickr. Agora, se eu quiser escrever um controlador que possa acessar o Flickr, só preciso me referir ao 'FlickrService' por nome quando declarar o controlador. O AngularJS cuidará de instanciar o componente e disponibilizá-lo ao meu controlador.
Por exemplo, aqui eu defino um serviço:
myApp.service('FlickrService', function() {
return {
getFeed: function() { // do something here }
}
});
Agora, quando eu quero usar esse serviço, apenas me refiro a ele por nome como este:
myApp.controller('myController', ['FlickrService', function(FlickrService) {
FlickrService.getFeed()
}]);
O AngularJS reconhecerá que um objeto FlickrService é necessário para instanciar o controlador e fornecerá um para nós.
Isso facilita muito a conexão das coisas e elimina praticamente qualquer tendência à spagetificação. Temos uma lista simples de componentes e o AngularJS os entrega um a um quando e quando precisamos deles.
Arquitetura de serviço modular
O jQuery diz muito pouco sobre como você deve organizar seu código. AngularJS tem opiniões.
O AngularJS fornece módulos nos quais você pode inserir seu código. Se você estiver escrevendo um script que fale com o Flickr, por exemplo, convém criar um módulo do Flickr para envolver todas as suas funções relacionadas ao Flickr. Os módulos podem incluir outros módulos (DI). Seu aplicativo principal geralmente é um módulo e isso deve incluir todos os outros módulos dos quais seu aplicativo dependerá.
Você obtém uma reutilização simples de código. Se quiser escrever outro aplicativo baseado no Flickr, basta incluir o módulo Flickr e pronto, você terá acesso a todas as funções relacionadas ao Flickr em seu novo aplicativo.
Os módulos contêm componentes AngularJS. Quando incluímos um módulo, todos os componentes desse módulo ficam disponíveis para nós como uma lista simples identificada por suas seqüências únicas . Podemos injetar esses componentes um no outro usando o mecanismo de injeção de dependência do AngularJS.
Resumindo
AngularJS e jQuery não são inimigos. É possível usar o jQuery dentro do AngularJS muito bem. Se você estiver usando bem o AngularJS (modelos, vinculação de dados, $ scope, diretivas etc.), descobrirá que precisa de muito menos jQuery do que poderia exigir.
A principal coisa a perceber é que seu modelo direciona seu aplicativo. Pare de tentar escrever grandes plugins que fazem tudo. Em vez disso, escreva pequenas diretivas que fazem uma coisa e, em seguida, escreva um modelo simples para conectá-las.
Pense menos em JavaScript discreto e, em vez disso, pense em termos de extensões HTML.
Meu livrinho
Fiquei tão empolgado com o AngularJS que escrevi um pequeno livro sobre ele, que você pode ler on-line http://nicholasjohnson.com/angular-book/ . Espero que seja útil.