AngularJS vs.JQuery
AngularJS y jQuery adoptan ideologías muy diferentes. Si viene de jQuery, puede encontrar algunas de las diferencias sorprendentes. Angular puede hacerte enojar.
Esto es normal, debes seguir adelante. Angular lo vale.
La gran diferencia (TLDR)
jQuery le ofrece un kit de herramientas para seleccionar bits arbitrarios del DOM y realizar cambios ad-hoc en ellos. Puedes hacer prácticamente todo lo que quieras pieza por pieza.
AngularJS en cambio te da un compilador .
Lo que esto significa es que AngularJS lee todo su DOM de arriba a abajo y lo trata como código, literalmente como instrucciones para el compilador. A medida que atraviesa el DOM, busca directivas específicas ( directivas del compilador) que le dicen al compilador AngularJS cómo comportarse y qué hacer. Las directivas son pequeños objetos llenos de JavaScript que pueden coincidir con atributos, etiquetas, clases o incluso comentarios.
Cuando el compilador Angular determina que una parte del DOM coincide con una directiva particular, llama a la función de directiva, pasándole el elemento DOM, cualquier atributo, el $ alcance actual (que es un almacén de variables local) y algunos otros bits útiles. Estos atributos pueden contener expresiones que pueden ser interpretadas por la Directiva, y que le dicen cómo representar y cuándo debe volver a dibujarse.
Las directivas pueden, a su vez, incorporar componentes angulares adicionales, como controladores, servicios, etc. Lo que sale de la parte inferior del compilador es una aplicación web completamente formada, cableada y lista para funcionar.
Esto significa que Angular es impulsado por plantilla . Su plantilla impulsa el JavaScript, no al revés. Esta es una inversión radical de roles, y todo lo contrario del discreto JavaScript que hemos estado escribiendo durante los últimos 10 años más o menos. Esto puede llevar un tiempo acostumbrarse.
Si esto suena como si fuera demasiado prescriptivo y limitante, nada podría estar más lejos de la verdad. Debido a que AngularJS trata su HTML como código, obtiene granularidad de nivel HTML en su aplicación web . Todo es posible, y la mayoría de las cosas son sorprendentemente fáciles una vez que haces algunos saltos conceptuales.
Vayamos a lo esencial.
Primero, Angular no reemplaza a jQuery
Angular y jQuery hacen cosas diferentes. AngularJS le brinda un conjunto de herramientas para producir aplicaciones web. jQuery le brinda principalmente herramientas para modificar el DOM. Si jQuery está presente en su página, AngularJS lo usará automáticamente. Si no es así, AngularJS se entrega con jQuery Lite, que es una versión reducida, pero aún perfectamente utilizable de jQuery.
A Misko le gusta jQuery y no se opone a que lo uses. Sin embargo, a medida que avance, encontrará que puede realizar casi todo su trabajo utilizando una combinación de alcance, plantillas y directivas, y debería preferir este flujo de trabajo cuando sea posible porque su código será más discreto, más configurable y más Angular.
Si usa jQuery, no debería rociarlo por todas partes. El lugar correcto para la manipulación DOM en AngularJS es en una directiva. Más sobre esto más adelante.
JavaScript discreto con selectores versus plantillas declarativas
jQuery generalmente se aplica discretamente. Su código JavaScript está vinculado en el encabezado (o pie de página), y este es el único lugar donde se menciona. Usamos selectores para seleccionar partes de la página y escribir complementos para modificar esas partes.
El JavaScript está en control. El HTML tiene una existencia completamente independiente. Su HTML sigue siendo semántico incluso sin JavaScript. Los atributos de Onclick son muy malas prácticas.
Una de las primeras cosas que notará sobre AngularJS es que los atributos personalizados están en todas partes . Su HTML estará lleno de atributos ng, que son esencialmente atributos onClick en esteroides. Estas son directivas (directivas del compilador) y son una de las principales formas en que la plantilla se engancha al modelo.
Cuando vea esto por primera vez, podría verse tentado a escribir AngularJS como JavaScript intrusivo de la vieja escuela (como lo hice al principio). De hecho, AngularJS no cumple con esas reglas. En AngularJS, su HTML5 es una plantilla. AngularJS lo compila para producir su página web.
Esta es la primera gran diferencia. Para jQuery, su página web es un DOM para ser manipulado. Para AngularJS, su HTML es el código que se compilará. AngularJS lee en toda su página web y literalmente lo compila en una nueva página web utilizando su compilador incorporado.
Su plantilla debe ser declarativa; su significado debe quedar claro simplemente al leerlo. Utilizamos atributos personalizados con nombres significativos. Creamos nuevos elementos HTML, nuevamente con nombres significativos. Un diseñador con un conocimiento mínimo de HTML y sin habilidad de codificación puede leer su plantilla AngularJS y comprender lo que está haciendo. Él o ella pueden hacer modificaciones. Este es el camino angular.
La plantilla está en el asiento del conductor.
Una de las primeras preguntas que me hice al iniciar AngularJS y ejecutar los tutoriales es "¿Dónde está mi código?" . No he escrito JavaScript y, sin embargo, tengo todo este comportamiento. La respuesta es obvia. Debido a que AngularJS compila el DOM, AngularJS está tratando su HTML como código. Para muchos casos simples, a menudo es suficiente escribir una plantilla y dejar que AngularJS la compile en una aplicación para usted.
Su plantilla impulsa su aplicación. Se trata como un DSL . Usted escribe los componentes de AngularJS, y AngularJS se encargará de incorporarlos y ponerlos a su disposición en el momento adecuado según la estructura de su plantilla. Esto es muy diferente a un patrón MVC estándar , donde la plantilla es solo para salida.
Es más similar a XSLT que Ruby on Rails, por ejemplo.
Esta es una inversión radical de control a la que lleva un tiempo acostumbrarse.
Deja de intentar manejar tu aplicación desde tu JavaScript. Deje que la plantilla controle la aplicación y deje que AngularJS se encargue de conectar los componentes entre sí. Esta también es la forma angular.
HTML semántico frente a modelos semánticos
Con jQuery, su página HTML debe contener contenido semántico significativo. Si JavaScript está desactivado (por un usuario o motor de búsqueda), su contenido permanecerá accesible.
Porque AngularJS trata su página HTML como una plantilla. Se supone que la plantilla no es semántica, ya que su contenido generalmente se almacena en su modelo, que en última instancia proviene de su API. AngularJS compila su DOM con el modelo para producir una página web semántica.
Su fuente HTML ya no es semántica, en cambio, su API y DOM compilado son semánticos.
En AngularJS, lo que significa vidas en el modelo, el HTML es solo una plantilla, solo para visualización.
En este punto, es probable que tenga todo tipo de preguntas sobre SEO y accesibilidad, y con razón. Hay problemas abiertos aquí. La mayoría de los lectores de pantalla ahora analizarán JavaScript. Los motores de búsqueda también pueden indexar contenido AJAXed . Sin embargo, querrá asegurarse de que está utilizando URL de estado de inserción y que tiene un mapa del sitio decente. Vea aquí para una discusión del problema: https://stackoverflow.com/a/23245379/687677
Separación de preocupaciones (SOC) vs. MVC
La separación de preocupaciones (SOC) es un patrón que creció durante muchos años de desarrollo web por una variedad de razones que incluyen SEO, accesibilidad e incompatibilidad del navegador. Se parece a esto:
- HTML: significado semántico. El HTML debe estar solo.
- CSS: estilo, sin el CSS, la página sigue siendo legible.
- JavaScript - Comportamiento, sin el script el contenido permanece.
Nuevamente, AngularJS no cumple con sus reglas. De un solo golpe, AngularJS elimina una década de sabiduría recibida y en su lugar implementa un patrón MVC en el que la plantilla ya no es semántica, ni siquiera un poco.
Se parece a esto:
- Modelo: sus modelos contienen sus datos semánticos. Los modelos suelen ser objetos JSON . Los modelos existen como atributos de un objeto llamado $ scope. También puede almacenar prácticas funciones de utilidad en $ scope a las que pueden acceder sus plantillas.
- Ver: sus vistas están escritas en HTML. La vista generalmente no es semántica porque sus datos viven en el modelo.
- Controlador: su controlador es una función de JavaScript que conecta la vista al modelo. Su función es inicializar $ scope. Dependiendo de su aplicación, es posible que necesite o no crear un controlador. Puede tener muchos controladores en una página.
MVC y SOC no están en extremos opuestos de la misma escala, están en ejes completamente diferentes. SOC no tiene sentido en un contexto AngularJS. Tienes que olvidarlo y seguir adelante.
Si, como yo, viviste la guerra de los navegadores, es posible que esta idea sea bastante ofensiva. Supéralo, valdrá la pena, lo prometo.
Complementos vs. Directivas
Los complementos extienden jQuery. Las directivas de AngularJS amplían las capacidades de su navegador.
En jQuery definimos complementos agregando funciones al jQuery.prototype. Luego los conectamos al DOM seleccionando elementos y llamando al complemento en el resultado. La idea es ampliar las capacidades de jQuery.
Por ejemplo, si desea un carrusel en su página, puede definir una lista desordenada de figuras, tal vez envuelta en un elemento de navegación. Luego, puede escribir un poco de jQuery para seleccionar la lista en la página y rediseñarla como una galería con tiempos de espera para hacer la animación deslizante.
En AngularJS, definimos directivas. Una directiva es una función que devuelve un objeto JSON. Este objeto le dice a AngularJS qué elementos DOM debe buscar y qué cambios hacer en ellos. Las directivas se conectan a la plantilla utilizando atributos o elementos, que usted inventa. La idea es ampliar las capacidades de HTML con nuevos atributos y elementos.
La forma AngularJS es extender las capacidades de HTML de aspecto nativo. Debe escribir HTML que se parezca a HTML, extendido con atributos y elementos personalizados.
Si desea un carrusel, simplemente use un <carousel />
elemento, luego defina una directiva para extraer una plantilla y haga que ese tonto funcione.
Muchas directivas pequeñas versus grandes complementos con conmutadores de configuración
La tendencia con jQuery es escribir grandes complementos grandes como lightbox que luego configuramos pasando numerosos valores y opciones.
Esto es un error en AngularJS.
Tome el ejemplo de un menú desplegable. Al escribir un complemento desplegable, puede tener la tentación de codificar en controladores de clics, tal vez una función para agregar un galón que esté hacia arriba o hacia abajo, tal vez cambiar la clase del elemento desplegado, mostrar ocultar el menú, todo lo útil.
Hasta que quieras hacer un pequeño cambio.
Digamos que tiene un menú que desea desplegar al pasar el mouse sobre él. Bueno, ahora tenemos un problema. Nuestro complemento se ha conectado en nuestro controlador de clics, necesitaremos agregar una opción de configuración para que se comporte de manera diferente en este caso específico.
En AngularJS escribimos directivas más pequeñas. Nuestra directiva desplegable sería ridículamente pequeña. Puede mantener el estado plegado y proporcionar métodos para plegar (), desplegar () o alternar (). Estos métodos simplemente actualizarían $ scope.menu.visible, que es un booleano que contiene el estado.
Ahora en nuestra plantilla podemos conectar esto:
<a ng-click="toggle()">Menu</a>
<ul ng-show="menu.visible">
...
</ul>
¿Necesita actualizar al pasar el mouse?
<a ng-mouseenter="unfold()" ng-mouseleave="fold()">Menu</a>
<ul ng-show="menu.visible">
...
</ul>
La plantilla impulsa la aplicación, por lo que obtenemos granularidad de nivel HTML. Si queremos hacer excepciones caso por caso, la plantilla lo hace fácil.
Cierre vs. $ alcance
Los complementos de JQuery se crean en un cierre. La privacidad se mantiene dentro de ese cierre. Depende de usted mantener su cadena de alcance dentro de ese cierre. Realmente solo tiene acceso al conjunto de nodos DOM pasados al complemento por jQuery, más cualquier variable local definida en el cierre y cualquier global que haya definido. Esto significa que los complementos son bastante independientes. Esto es algo bueno, pero puede ser restrictivo al crear una aplicación completa. Intentar pasar datos entre secciones de una página dinámica se convierte en una tarea difícil.
AngularJS tiene objetos $ scope. Estos son objetos especiales creados y mantenidos por AngularJS en los que almacena su modelo. Ciertas directivas generarán un nuevo $ scope, que por defecto hereda de su envoltorio $ scope usando la herencia prototípica de JavaScript. Se puede acceder al objeto $ scope en el controlador y la vista.
Esta es la parte inteligente. Debido a que la estructura de la herencia de $ alcance sigue aproximadamente la estructura del DOM, los elementos tienen acceso a su propio alcance, y a cualquier ámbito que contenga sin problemas, hasta el $ alcance global (que no es lo mismo que el alcance global).
Esto hace que sea mucho más fácil pasar datos y almacenar datos en un nivel apropiado. Si se despliega un menú desplegable, solo el menú desplegable $ scope debe saberlo. Si el usuario actualiza sus preferencias, es posible que desee actualizar el alcance global $, y cualquier ámbito anidado que escuche las preferencias del usuario será alertado automáticamente.
Esto puede sonar complicado, de hecho, una vez que te relajas, es como volar. No necesita crear el objeto $ scope, AngularJS lo instancia y configura por usted, de manera correcta y apropiada según la jerarquía de su plantilla. AngularJS lo pone a disposición de su componente utilizando la magia de la inyección de dependencia (más sobre esto más adelante).
Cambios manuales de DOM versus enlace de datos
En jQuery haces todos tus cambios DOM a mano. Construye nuevos elementos DOM programáticamente. Si tiene una matriz JSON y desea ponerla en el DOM, debe escribir una función para generar el HTML e insertarlo.
En AngularJS también puede hacerlo, pero le recomendamos que utilice el enlace de datos. Cambie su modelo, y debido a que el DOM está vinculado a él a través de una plantilla, su DOM se actualizará automáticamente, no se requiere intervención.
Debido a que el enlace de datos se realiza desde la plantilla, utilizando un atributo o la sintaxis de llaves, es muy fácil de hacer. Hay poca sobrecarga cognitiva asociada, por lo que te encontrarás haciéndolo todo el tiempo.
<input ng-model="user.name" />
Vincula el elemento de entrada a $scope.user.name
. La actualización de la entrada actualizará el valor en su alcance actual, y viceversa.
Igualmente:
<p>
{{user.name}}
</p>
mostrará el nombre de usuario en un párrafo. Es un enlace en vivo, por lo que si el $scope.user.name
valor se actualiza, la plantilla también se actualizará.
Ajax todo el tiempo
En jQuery, hacer una llamada Ajax es bastante simple, pero aún es algo en lo que podrías pensar dos veces. Hay una complejidad adicional en la que pensar, y una buena parte del guión que mantener.
En AngularJS, Ajax es su solución predeterminada y ocurre todo el tiempo, casi sin que lo note. Puede incluir plantillas con ng-include. Puede aplicar una plantilla con la directiva personalizada más simple. Puede ajustar una llamada Ajax en un servicio y crearse un servicio GitHub o un servicio Flickr , al que puede acceder con asombrosa facilidad.
Objetos de servicio frente a funciones auxiliares
En jQuery, si queremos realizar una pequeña tarea no relacionada con dom, como extraer un feed de una API, podríamos escribir una pequeña función para hacerlo en nuestro cierre. Esa es una solución válida, pero ¿qué pasa si queremos acceder a ese feed a menudo? ¿Qué pasa si queremos reutilizar ese código en otra aplicación?
AngularJS nos da objetos de servicio.
Los servicios son objetos simples que contienen funciones y datos. Siempre son singletons, lo que significa que nunca puede haber más de uno. Supongamos que queremos acceder a la API de desbordamiento de pila, podríamos escribir una StackOverflowService
que defina los métodos para hacerlo.
Digamos que tenemos un carrito de compras. Podríamos definir un ShoppingCartService que mantiene nuestro carrito y contiene métodos para agregar y eliminar artículos. Debido a que el servicio es un singleton y es compartido por todos los demás componentes, cualquier objeto que necesite puede escribir en el carrito de compras y extraer datos de él. Siempre es el mismo carrito.
Los objetos de servicio son componentes independientes de AngularJS que podemos usar y reutilizar como mejor nos parezca. Son simples objetos JSON que contienen funciones y datos. Siempre son singletons, por lo que si almacena datos en un servicio en un lugar, puede obtener esos datos en otro lugar simplemente solicitando el mismo servicio.
Inyección de dependencia (DI) vs. Instatiation - también conocido como desespaguetificación
AngularJS gestiona tus dependencias por ti. Si desea un objeto, simplemente consúltelo y AngularJS lo obtendrá por usted.
Hasta que empiece a usar esto, es difícil explicar qué tan enorme es la bendición del tiempo. Nada como AngularJS DI existe dentro de jQuery.
DI significa que, en lugar de escribir su aplicación y conectarla, define una biblioteca de componentes, cada uno identificado por una cadena.
Digamos que tengo un componente llamado 'FlickrService' que define métodos para extraer feeds JSON de Flickr. Ahora, si quiero escribir un controlador que pueda acceder a Flickr, solo necesito referirme al 'FlickrService' por nombre cuando declaro el controlador. AngularJS se encargará de crear instancias del componente y ponerlo a disposición de mi controlador.
Por ejemplo, aquí defino un servicio:
myApp.service('FlickrService', function() {
return {
getFeed: function() { // do something here }
}
});
Ahora, cuando quiero usar ese servicio, solo me refiero a él por este nombre:
myApp.controller('myController', ['FlickrService', function(FlickrService) {
FlickrService.getFeed()
}]);
AngularJS reconocerá que se necesita un objeto FlickrService para crear una instancia del controlador, y nos proporcionará uno.
Esto hace que el cableado de las cosas sea muy fácil, y prácticamente elimina cualquier tendencia a la spagettificación. Tenemos una lista plana de componentes, y AngularJS nos los entrega uno por uno a medida que los necesitamos.
Arquitectura de servicio modular.
jQuery dice muy poco sobre cómo debe organizar su código. AngularJS tiene opiniones.
AngularJS le proporciona módulos en los que puede colocar su código. Si está escribiendo una secuencia de comandos que habla con Flickr, por ejemplo, es posible que desee crear un módulo Flickr para envolver todas sus funciones relacionadas con Flickr. Los módulos pueden incluir otros módulos (DI). Su aplicación principal suele ser un módulo, y esto debe incluir todos los demás módulos de los que dependerá su aplicación.
Obtiene una reutilización de código simple, si desea escribir otra aplicación basada en Flickr, simplemente puede incluir el módulo Flickr y listo, tiene acceso a todas sus funciones relacionadas con Flickr en su nueva aplicación.
Los módulos contienen componentes AngularJS. Cuando incluimos un módulo, todos los componentes en ese módulo están disponibles para nosotros como una lista simple identificada por sus cadenas únicas . Luego podemos inyectar esos componentes entre sí utilizando el mecanismo de inyección de dependencia de AngularJS.
Para resumir
AngularJS y jQuery no son enemigos. Es posible usar jQuery dentro de AngularJS muy bien. Si está utilizando bien AngularJS (plantillas, enlace de datos, $ scope, directivas, etc.), encontrará que necesita mucho menos jQuery de lo que podría necesitar.
Lo principal a tener en cuenta es que su plantilla impulsa su aplicación. Deja de intentar escribir grandes complementos que hagan todo. En su lugar, escriba pequeñas directivas que hagan una cosa, luego escriba una plantilla simple para unirlas.
Piense menos en JavaScript discreto y, en cambio, piense en términos de extensiones HTML.
Mi librito
Me emocioné tanto con AngularJS que escribí un breve libro sobre él que pueden leer en línea en http://nicholasjohnson.com/angular-book/ . Espero que sea útil.