¿"Pensando en AngularJS" si tengo experiencia en jQuery? [cerrado]
Supongamos que estoy familiarizado con el desarrollo de aplicaciones del lado del cliente en jQuery , pero ahora me gustaría comenzar a usar AngularJS . ¿Puede describir el cambio de paradigma que es necesario? Aquí hay algunas preguntas que pueden ayudarlo a formular una respuesta:
- ¿Cómo puedo diseñar y diseñar aplicaciones web del lado del cliente de manera diferente? ¿Cuál es la mayor diferencia?
- ¿Qué debo dejar de hacer / usar? ¿Qué debería empezar a hacer / usar en su lugar?
- ¿Existen consideraciones / restricciones del lado del servidor?
No busco una comparación detallada entre jQuery
y AngularJS
.
Respuestas
1. No diseñe su página y luego cámbiela con manipulaciones DOM
En jQuery, diseñas una página y luego la haces dinámica. Esto se debe a que jQuery fue diseñado para el aumento y ha crecido increíblemente a partir de esa simple premisa.
Pero en AngularJS, debe comenzar desde cero con su arquitectura en mente. En lugar de empezar pensando "Tengo esta parte del DOM y quiero hacer que funcione X", tienes que empezar con lo que quieres lograr, luego diseñar tu aplicación y finalmente diseñar tu vista.
2. No aumente jQuery con AngularJS
De manera similar, no comience con la idea de que jQuery hace X, Y y Z, así que solo agregaré AngularJS además de eso para modelos y controladores. Esto es realmente tentador cuando recién está comenzando, por lo que siempre recomiendo que los nuevos desarrolladores de AngularJS no usen jQuery en absoluto, al menos hasta que se acostumbren a hacer las cosas de la "manera angular".
He visto a muchos desarrolladores aquí y en la lista de correo crear estas soluciones elaboradas con complementos de jQuery de 150 o 200 líneas de código que luego pegan en AngularJS con una colección de devoluciones de llamada y mensajes de correo electrónico $apply
que son confusos y complicados; ¡pero eventualmente lo hacen funcionar! El problema es que, en la mayoría de los casos, el complemento jQuery podría reescribirse en AngularJS en una fracción del código, donde de repente todo se vuelve comprensible y sencillo.
La conclusión es la siguiente: al realizar la solución, primero "piense en AngularJS"; si no puede pensar en una solución, pregunte a la comunidad; Si después de todo esto no hay una solución fácil, entonces no dude en alcanzar el jQuery. Pero no dejes que jQuery se convierta en una muleta o nunca dominarás AngularJS.
3. Piensa siempre en términos de arquitectura
Primero, sepa que las aplicaciones de una sola página son aplicaciones . Son no páginas web. Por lo tanto, debemos pensar como un desarrollador del lado del servidor además de pensar como un desarrollador del lado del cliente. Tenemos que pensar en cómo dividir nuestra aplicación en componentes individuales, extensibles y probables.
Entonces, ¿cómo haces eso? ¿Cómo "piensas en AngularJS"? A continuación, se muestran algunos principios generales, en contraste con jQuery.
La vista es el "registro oficial"
En jQuery, cambiamos la vista mediante programación. Podríamos tener un menú desplegable definido ul
como así:
<ul class="main-menu">
<li class="active">
<a href="#/home">Home</a>
</li>
<li>
<a href="#/menu1">Menu 1</a>
<ul>
<li><a href="#/sm1">Submenu 1</a></li>
<li><a href="#/sm2">Submenu 2</a></li>
<li><a href="#/sm3">Submenu 3</a></li>
</ul>
</li>
<li>
<a href="#/home">Menu 2</a>
</li>
</ul>
En jQuery, en nuestra lógica de aplicación, lo activaríamos con algo como:
$('.main-menu').dropdownMenu();
Cuando solo miramos la vista, no es inmediatamente obvio que haya alguna funcionalidad aquí. Para aplicaciones pequeñas, está bien. Pero para las aplicaciones no triviales, las cosas rápidamente se vuelven confusas y difíciles de mantener.
En AngularJS, sin embargo, la vista es el registro oficial de la funcionalidad basada en vista. En su lugar, nuestra ul
declaración se vería así:
<ul class="main-menu" dropdown-menu>
...
</ul>
Estos dos hacen lo mismo, pero en la versión de AngularJS cualquiera que mire la plantilla sabe lo que se supone que debe suceder. Cada vez que se incorpora un nuevo miembro del equipo de desarrollo, puede ver esto y saber que existe una directiva que se llama dropdownMenu
operar en él; no necesita intuir la respuesta correcta ni examinar ningún código. La vista nos dijo lo que se suponía que iba a pasar. Mucho más limpio.
Los desarrolladores nuevos en AngularJS a menudo hacen una pregunta como: ¿cómo encuentro todos los enlaces de un tipo específico y les agrego una directiva? El desarrollador siempre se queda atónito cuando respondemos: tú no. Pero la razón por la que no lo hace es que esto es como mitad jQuery, mitad AngularJS y no es bueno. El problema aquí es que el desarrollador está intentando "hacer jQuery" en el contexto de AngularJS. Eso nunca va a funcionar bien. La vista es el registro oficial. Fuera de una directiva (más sobre esto a continuación), nunca, nunca, nunca cambia el DOM. Y las directivas se aplican en la vista , por lo que la intención es clara.
Recuerde: no diseñe y luego marque. Debes diseñar y luego diseñar.
El enlace de datos
Esta es, con mucho, una de las características más impresionantes de AngularJS y elimina gran parte de la necesidad de realizar los tipos de manipulaciones DOM que mencioné en la sección anterior. AngularJS actualizará automáticamente su vista para que usted no tenga que hacerlo. En jQuery, respondemos a eventos y luego actualizamos el contenido. Algo como:
$.ajax({ url: '/myEndpoint.json', success: function ( data, status ) { $('ul#log').append('<li>Data Received!</li>');
}
});
Para obtener una vista similar a esta:
<ul class="messages" id="log">
</ul>
Además de mezclar preocupaciones, también tenemos los mismos problemas de intención significante que mencioné antes. Pero lo que es más importante, tuvimos que hacer referencia y actualizar manualmente un nodo DOM. Y si queremos eliminar una entrada de registro, también tenemos que codificar contra el DOM. ¿Cómo probamos la lógica aparte del DOM? ¿Y si queremos cambiar la presentación?
Esto un poco desordenado y un poco frágil. Pero en AngularJS, podemos hacer esto:
$http( '/myEndpoint.json' ).then( function ( response ) { $scope.log.push( { msg: 'Data Received!' } );
});
Y nuestra vista puede verse así:
<ul class="messages">
<li ng-repeat="entry in log">{{ entry.msg }}</li>
</ul>
Pero para el caso, nuestra vista podría verse así:
<div class="messages">
<div class="alert" ng-repeat="entry in log">
{{ entry.msg }}
</div>
</div>
Y ahora, en lugar de usar una lista desordenada, estamos usando cuadros de alerta de Bootstrap. ¡Y nunca tuvimos que cambiar el código del controlador! Pero lo que es más importante, no importa dónde o cómo se actualice el registro, la vista también cambiará. Automáticamente. ¡Limpio!
Aunque no lo mostré aquí, el enlace de datos es bidireccional. Así que los mensajes de registro también podría ser modificable en la vista sólo por hacer esto: <input ng-model="entry.msg" />
. Y hubo mucho regocijo.
Capa de modelo distinta
En jQuery, el DOM es como el modelo. Pero en AngularJS, tenemos una capa de modelo separada que podemos administrar de la forma que queramos, de forma completamente independiente de la vista. Esto ayuda a la vinculación de datos anterior, mantiene la separación de preocupaciones e introduce una capacidad de prueba mucho mayor. Otras respuestas mencionaron este punto, así que lo dejaré así.
Separación de intereses
Y todo lo anterior se relaciona con este tema general: mantenga sus preocupaciones separadas. Su punto de vista actúa como el registro oficial de lo que se supone que debe suceder (en su mayor parte); su modelo representa sus datos; tiene una capa de servicio para realizar tareas reutilizables; realiza manipulación DOM y aumenta su vista con directivas; y lo pegas todo junto con los controladores. Esto también se mencionó en otras respuestas, y lo único que agregaría se refiere a la capacidad de prueba, que discuto en otra sección a continuación.
Inyección de dependencia
Para ayudarnos con la separación de preocupaciones está la inyección de dependencia (DI). Si viene de un lenguaje del lado del servidor (de Java a PHP ) probablemente ya esté familiarizado con este concepto, pero si es un tipo del lado del cliente que viene de jQuery, este concepto puede parecer cualquier cosa, desde tonto hasta superfluo o hipster. . Pero no lo es. :-)
Desde una perspectiva amplia, DI significa que puede declarar componentes con mucha libertad y luego desde cualquier otro componente, simplemente solicite una instancia y se le otorgará. No es necesario que sepas sobre el orden de carga, la ubicación de los archivos ni nada por el estilo. Es posible que el poder no sea visible de inmediato, pero solo proporcionaré un ejemplo (común): prueba.
Digamos que en nuestra aplicación, necesitamos un servicio que implemente el almacenamiento del lado del servidor a través de una API REST y, según el estado de la aplicación, también el almacenamiento local. Cuando realizamos pruebas en nuestros controladores, no queremos tener que comunicarnos con el servidor ; después de todo, estamos probando el controlador . Podemos simplemente agregar un servicio simulado del mismo nombre que nuestro componente original, y el inyector se asegurará de que nuestro controlador obtenga el falso automáticamente; nuestro controlador no lo hace y no necesita saber la diferencia.
Hablando de pruebas ...
4. Desarrollo basado en pruebas: siempre
Esto es realmente parte de la sección 3 sobre arquitectura, pero es tan importante que lo estoy poniendo como su propia sección de nivel superior.
De todos los complementos de jQuery que ha visto, usado o escrito, ¿cuántos de ellos tenían un conjunto de pruebas adjunto? No muchos porque jQuery no es muy receptivo a eso. Pero AngularJS lo es.
En jQuery, la única forma de probar es a menudo crear el componente de forma independiente con una página de muestra / demostración en la que nuestras pruebas pueden realizar la manipulación DOM. Entonces tenemos que desarrollar un componente por separado y luego integrarlo en nuestra aplicación. ¡Qué inconveniente! La mayor parte del tiempo, cuando desarrollamos con jQuery, optamos por un desarrollo iterativo en lugar de basado en pruebas. ¿Y quién podría culparnos?
Pero debido a que tenemos una separación de preocupaciones, ¡podemos hacer un desarrollo basado en pruebas de forma iterativa en AngularJS! Por ejemplo, digamos que queremos una directiva súper simple para indicar en nuestro menú cuál es nuestra ruta actual. Podemos declarar lo que queremos en la vista de nuestra aplicación:
<a href="/hello" when-active>Hello</a>
Bien, ahora podemos escribir una prueba para la when-active
directiva inexistente :
it( 'should add "active" when the route changes', inject(function() {
var elm = $compile( '<a href="/hello" when-active>Hello</a>' )( $scope );
$location.path('/not-matching'); expect( elm.hasClass('active') ).toBeFalsey(); $location.path( '/hello' );
expect( elm.hasClass('active') ).toBeTruthy();
}));
Y cuando ejecutamos nuestra prueba, podemos confirmar que falla. Solo ahora deberíamos crear nuestra directiva:
.directive( 'whenActive', function ( $location ) { return { scope: true, link: function ( scope, element, attrs ) { scope.$on( '$routeChangeSuccess', function () { if ( $location.path() == element.attr( 'href' ) ) {
element.addClass( 'active' );
}
else {
element.removeClass( 'active' );
}
});
}
};
});
Nuestra prueba ahora pasa y nuestro menú funciona según lo solicitado. Nuestro desarrollo es tanto iterativo y basado en pruebas. Malvado-genial.
5. Conceptualmente, las directivas no están empaquetadas con jQuery
A menudo escuchará "solo hacer manipulación DOM en una directiva". Esta es una necesidad. ¡Trátelo con la debida deferencia!
Pero profundicemos un poco más ...
Algunas directivas simplemente decoran lo que ya está en la vista (piense ngClass
) y, por lo tanto, a veces realizan la manipulación DOM de inmediato y luego básicamente se hacen. Pero si una directiva es como un "Widget" y tiene una plantilla, debe también respetar la separación de preocupaciones. Es decir, la plantilla también debe permanecer en gran medida independiente de su implementación en las funciones de enlace y controlador.
AngularJS viene con un conjunto completo de herramientas para hacer esto muy fácil; con ngClass
podemos actualizar dinámicamente la clase; ngModel
permite el enlace de datos bidireccional; ngShow
y ngHide
mostrar u ocultar un elemento mediante programación; y muchos más, incluidos los que escribimos nosotros mismos. En otras palabras, podemos hacer todo tipo de maravillas sin manipulación de DOM. Cuanto menos manipulación DOM, más fáciles de probar las directivas, más fáciles de diseñar, más fáciles de cambiar en el futuro y más reutilizables y distribuibles son.
Veo a muchos desarrolladores nuevos en AngularJS que usan directivas como el lugar para lanzar un montón de jQuery. En otras palabras, piensan "ya que no puedo manipular DOM en el controlador, tomaré ese código y lo pondré en una directiva". Si bien eso ciertamente es mucho mejor, a menudo sigue siendo incorrecto .
Piense en el registrador que programamos en la sección 3. Incluso si ponemos eso en una directiva, todavía queremos hacerlo de la "manera angular". ¡ Todavía no necesita ninguna manipulación DOM! Hay muchas ocasiones en las que es necesaria la manipulación del DOM, ¡pero es mucho más raro de lo que piensas! Antes de realizar la manipulación DOM en cualquier parte de su aplicación, pregúntese si realmente lo necesita. Puede que haya una forma mejor.
Aquí hay un ejemplo rápido que muestra el patrón que veo con más frecuencia. Queremos un botón conmutable. (Nota: este ejemplo es un poco artificial y muy detallado para representar casos más complicados que se resuelven exactamente de la misma manera).
.directive( 'myDirective', function () {
return {
template: '<a class="btn">Toggle me!</a>',
link: function ( scope, element, attrs ) {
var on = false;
$(element).click( function () { on = !on; $(element).toggleClass('active', on);
});
}
};
});
Hay algunas cosas mal en esto:
- Primero, jQuery nunca fue necesario. ¡No hay nada que hicimos aquí que necesitara jQuery en absoluto!
- En segundo lugar, incluso si ya tenemos jQuery en nuestra página, no hay razón para usarlo aquí; simplemente podemos usar
angular.element
y nuestro componente seguirá funcionando cuando se coloque en un proyecto que no tiene jQuery. - En tercer lugar, incluso suponiendo que se requiera jQuery para que funcione esta directiva, ¡jqLite (
angular.element
) siempre usará jQuery si se cargó! Entonces no necesitamos usar el$
- podemos usarangular.element
. - Cuarto, estrechamente relacionado con el tercero, es que los elementos jqLite no necesitan estar envueltos
$
- ¡loelement
que se pasa a lalink
función ya sería un elemento jQuery! - Y quinto, que hemos mencionado en secciones anteriores, ¿por qué estamos mezclando elementos de plantilla en nuestra lógica?
Esta directiva se puede reescribir (¡incluso para casos muy complicados!) Mucho más simplemente así:
.directive( 'myDirective', function () {
return {
scope: true,
template: '<a class="btn" ng-class="{active: on}" ng-click="toggle()">Toggle me!</a>',
link: function ( scope, element, attrs ) {
scope.on = false;
scope.toggle = function () {
scope.on = !scope.on;
};
}
};
});
Nuevamente, el material de la plantilla está en la plantilla, por lo que usted (o sus usuarios) pueden cambiarlo fácilmente por uno que cumpla con cualquier estilo necesario, y la lógica nunca tuvo que ser tocada. Reutilización - ¡boom!
Y todavía existen todos esos otros beneficios, como las pruebas, ¡es fácil! No importa lo que haya en la plantilla, la API interna de la directiva nunca se toca, por lo que la refactorización es fácil. Puede cambiar la plantilla tanto como desee sin tocar la directiva. Y no importa lo que cambie, sus pruebas aún pasan.
w00t!
Entonces, si las directivas no son solo colecciones de funciones similares a jQuery, ¿qué son? Las directivas son en realidad extensiones de HTML . Si HTML no hace algo que usted necesita que haga, escribe una directiva para que lo haga por usted y luego lo usa como si fuera parte de HTML.
Dicho de otra manera, si AngularJS no hace algo fuera de la caja, piense cómo el equipo lograría que se ajuste perfectamente con ngClick
, ngClass
et al.
Resumen
Ni siquiera uses jQuery. Ni siquiera lo incluyas. Te detendrá. Y cuando llegue a un problema que cree que ya sabe cómo resolver en jQuery, antes de buscar el $
, intente pensar cómo hacerlo dentro de los límites de AngularJS. Si no lo sabe, ¡pregunte! 19 de cada 20 veces, la mejor manera de hacerlo no necesita jQuery y tratar de resolverlo con jQuery da como resultado más trabajo para usted.
Imperativo → declarativo
En jQuery, los selectores se utilizan para encontrar elementos DOM y luego vincular / registrar controladores de eventos a ellos. Cuando se activa un evento, ese código (imperativo) se ejecuta para actualizar / cambiar el DOM.
En AngularJS, desea pensar en vistas en lugar de elementos DOM. Las vistas son HTML (declarativas) que contienen directivas AngularJS . Las directivas configuran los controladores de eventos detrás de escena para nosotros y nos brindan un enlace de datos dinámico. Los selectores rara vez se utilizan, por lo que la necesidad de ID (y algunos tipos de clases) se reduce enormemente. Las vistas están vinculadas a modelos (a través de ámbitos). Las vistas son una proyección del modelo. Los eventos cambian los modelos (es decir, los datos, las propiedades del alcance) y las vistas que proyectan esos modelos se actualizan "automáticamente".
En AngularJS, piense en modelos, en lugar de elementos DOM seleccionados por jQuery que contienen sus datos. Piense en las vistas como proyecciones de esos modelos, en lugar de registrar devoluciones de llamada para manipular lo que ve el usuario.
Separación de intereses
jQuery emplea JavaScript discreto : el comportamiento (JavaScript) está separado de la estructura (HTML).
AngularJS usa controladores y directivas (cada uno de los cuales puede tener su propio controlador y / o funciones de compilación y vinculación) para eliminar el comportamiento de la vista / estructura (HTML). Angular también tiene servicios y filtros para ayudar a separar / organizar su aplicación.
Ver también https://stackoverflow.com/a/14346528/215945
Diseño de aplicaciones
Un enfoque para diseñar una aplicación AngularJS:
- Piense en sus modelos. Cree servicios o sus propios objetos JavaScript para esos modelos.
- Piense en cómo desea presentar sus modelos: sus puntos de vista. Cree plantillas HTML para cada vista, utilizando las directivas necesarias para obtener un enlace de datos dinámico.
- Adjunte un controlador a cada vista (usando ng-view y enrutamiento, o ng-controller). Haga que el controlador busque / obtenga solo los datos del modelo que la vista necesita para hacer su trabajo. Haga que los controladores sean lo más delgados posible.
Herencia prototípica
Puede hacer mucho con jQuery sin saber cómo funciona la herencia de prototipos de JavaScript. Al desarrollar aplicaciones AngularJS, evitará algunos errores comunes si tiene un buen conocimiento de la herencia de JavaScript. Lectura recomendada: ¿Cuáles son los matices de la herencia prototípica / prototípica de alcance en AngularJS?
AngularJS frente a jQuery
AngularJS y jQuery adoptan ideologías muy diferentes. Si vienes de jQuery, es posible que algunas de las diferencias te resulten sorprendentes. Angular puede hacerte enojar.
Esto es normal, debes seguir adelante. Angular lo vale.
La gran diferencia (TLDR)
jQuery le brinda un conjunto de herramientas para seleccionar bits arbitrarios del DOM y realizar cambios ad-hoc en ellos. Puedes hacer casi todo lo que quieras pieza por pieza.
En cambio, AngularJS le ofrece 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 en particular, llama a la función directiva, pasándole el elemento DOM, cualquier atributo, el $ scope actual (que es un almacén de variables locales) y algunos otros bits útiles. Estos atributos pueden contener expresiones que pueden ser interpretadas por la Directiva y que le indican 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 aparece en la parte inferior del compilador es una aplicación web completamente formada, conectada y lista para funcionar.
Esto significa que Angular se basa en plantillas . Su plantilla maneja JavaScript, no al revés. Esta es una inversión radical de roles, y todo lo contrario del JavaScript discreto que hemos estado escribiendo durante los últimos 10 años más o menos. Esto puede tomar algún tiempo para acostumbrarse.
Si esto parece ser 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 das algunos saltos conceptuales.
Vayamos al meollo de la cuestión.
Primero, Angular no reemplaza a jQuery
Angular y jQuery hacen cosas diferentes. AngularJS le brinda un conjunto de herramientas para producir aplicaciones web. jQuery principalmente le brinda herramientas para modificar el DOM. Si jQuery está presente en su página, AngularJS lo usará automáticamente. Si no es así, AngularJS se envía con jQuery Lite, que es una versión reducida, pero perfectamente utilizable, de jQuery.
A Misko le gusta jQuery y no se opone a que lo use. Sin embargo, a medida que avanza, encontrará que puede realizar casi todo su trabajo utilizando una combinación de alcance, plantillas y directivas, y debe preferir este flujo de trabajo siempre que sea posible porque su código será más discreto, más configurable y más. Angular.
Si usa jQuery, no debería esparcirlo por todos lados. El lugar correcto para la manipulación de DOM en AngularJS es una directiva. Más sobre estos más adelante.
JavaScript discreto con selectores frente a plantillas declarativas
Por lo general, jQuery se aplica de forma discreta. 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 escribimos complementos para modificar esas partes.
El JavaScript tiene el control. El HTML tiene una existencia completamente independiente. Su HTML permanece semántico incluso sin JavaScript. Los atributos de un clic son una práctica muy mala.
Una de las primeras cosas que notará sobre AngularJS es que los atributos personalizados están en todas partes . Su HTML estará plagado de atributos ng, que son esencialmente atributos onClick en esteroides. Estas son directivas (directivas del compilador) y son una de las principales formas en las que la plantilla se conecta al modelo.
Cuando vea esto por primera vez, puede tener la tentación de descartar AngularJS como JavaScript intrusivo de la vieja escuela (como hice al principio). De hecho, AngularJS no sigue esas reglas. En AngularJS, su HTML5 es una plantilla. Está compilado por AngularJS para producir su página web.
Ésta es la primera gran diferencia. Para jQuery, su página web es un DOM para ser manipulado. Para AngularJS, su HTML es un código que se compilará. AngularJS lee toda su página web y, literalmente, la compila en una nueva página web utilizando su compilador integrado.
Tu plantilla debe ser declarativa; su significado debe quedar claro simplemente leyéndolo. Usamos 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 habilidades de codificación puede leer su plantilla AngularJS y comprender lo que está haciendo. Él o ella pueden hacer modificaciones. Esta es la forma 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 trata 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 hacerlos disponibles 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 a Ruby on Rails, por ejemplo.
Esta es una inversión radical del control a la que cuesta acostumbrarse.
Deje de intentar manejar su aplicación desde su JavaScript. Deje que la plantilla dirija la aplicación y deje que AngularJS se encargue de conectar los componentes. 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 un motor de búsqueda), su contenido permanece 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 que vive 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 AJAX . Sin embargo, querrá asegurarse de que está utilizando URL pushstate y tiene un mapa del sitio decente. Consulte aquí para ver una discusión sobre el tema:https://stackoverflow.com/a/23245379/687677
Separación de preocupaciones (SOC) vs. MVC
La separación de preocupaciones (SOC) es un patrón que se desarrolló 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 debería ser independiente.
- CSS: estilo, sin CSS la página aún es legible.
- JavaScript: comportamiento, sin el script el contenido permanece.
Una vez más, AngularJS no sigue sus reglas. De un golpe, AngularJS acaba con 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 poquito.
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.
- Vista: 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 enlaza 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 las guerras de los navegadores, es posible que esta idea te resulte bastante ofensiva. Supéralo, valdrá la pena, te lo prometo.
Complementos frente a directivas
Los complementos amplían jQuery. Las directivas 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 de figuras desordenada, quizás envuelta en un elemento de navegación. Luego, puede escribir algo de jQuery para seleccionar la lista en la página y cambiarle el estilo 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 buscar y qué cambios hacer en ellos. Las directivas se enlazan 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 de AngularJS es ampliar las capacidades del HTML de aspecto nativo. Debe escribir HTML que se parezca a HTML, ampliado con atributos y elementos personalizados.
Si desea un carrusel, solo use un <carousel />
elemento, luego defina una directiva para extraer una plantilla y hacer que funcione.
Muchas directivas pequeñas frente a grandes complementos con conmutadores de configuración
La tendencia con jQuery es escribir grandes complementos como lightbox que luego configuramos pasando numerosos valores y opciones.
Este es un error en AngularJS.
Tome el ejemplo de un menú desplegable. Al escribir un complemento desplegable, es posible que tenga la tentación de codificar en controladores de clics, tal vez una función para agregar un cheuró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.
Supongamos que tiene un menú que desea desplegar al pasar el mouse. Bueno, ahora tenemos un problema. Nuestro complemento se ha conectado en nuestro controlador de clics para nosotros, 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>
¿Necesitas actualizar al pasar el mouse por encima?
<a ng-mouseenter="unfold()" ng-mouseleave="fold()">Menu</a>
<ul ng-show="menu.visible">
...
</ul>
La plantilla controla la aplicación, por lo que obtenemos granularidad de nivel HTML. Si queremos hacer excepciones caso por caso, la plantilla lo facilita.
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 autónomos. Esto es bueno, pero puede volverse restrictivo al crear una aplicación completa. Intentar pasar datos entre secciones de una página dinámica se convierte en una tarea ardua.
AngularJS tiene $scope objects. These are special objects created and maintained by AngularJS in which you store your model. Certain directives will spawn a new $alcance, que por defecto hereda de su envoltura $scope using JavaScript prototypical inheritance. The $El objeto de alcance es accesible en el controlador y la vista.
Esta es la parte inteligente. Porque la estructura de$scope inheritance roughly follows the structure of the DOM, elements have access to their own scope, and any containing scopes seamlessly, all the way up to the global $alcance (que no es el 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 needs to know about it. If the user updates their preferences, you might want to update the global $alcance, y cualquier alcance anidado que escuche las preferencias del usuario recibiría una alerta automáticamente.
Esto puede parecer complicado, de hecho, una vez que te relajas, es como volar. No necesita crear el objeto $ scope, AngularJS crea una instancia y lo configura por usted, de manera correcta y apropiada según la jerarquía de su plantilla. AngularJS luego 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 de DOM manuales frente a vinculación de datos
En jQuery, realiza todos los cambios de DOM a mano. Construyes nuevos elementos DOM mediante programación. Si tiene una matriz JSON y desea colocarla en el DOM, debe escribir una función para generar el HTML e insertarlo.
En AngularJS también puede hacer esto, 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, sin necesidad de intervención.
Debido a que el enlace de datos se realiza desde la plantilla, usando un atributo o la sintaxis de llaves, es muy fácil de hacer. Hay poca sobrecarga cognitiva asociada con él, por lo que se encontrará 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>
generará 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 all of the time
In jQuery making an Ajax call is fairly simple, but it's still something you might think twice about. There's the added complexity to think about, and a fair chunk of script to maintain.
In AngularJS, Ajax is your default go-to solution and it happens all the time, almost without you noticing. You can include templates with ng-include. You can apply a template with the simplest custom directive. You can wrap an Ajax call in a service and create yourself a GitHub service, or a Flickr service, which you can access with astonishing ease.
Service Objects vs Helper Functions
In jQuery, if we want to accomplish a small non-dom related task such as pulling a feed from an API, we might write a little function to do that in our closure. That's a valid solution, but what if we want to access that feed often? What if we want to reuse that code in another application?
AngularJS gives us service objects.
Services are simple objects that contain functions and data. They are always singletons, meaning there can never be more than one of them. Say we want to access the Stack Overflow API, we might write a StackOverflowService
which defines methods for doing so.
Let's say we have a shopping cart. We might define a ShoppingCartService which maintains our cart and contains methods for adding and removing items. Because the service is a singleton, and is shared by all other components, any object that needs to can write to the shopping cart and pull data from it. It's always the same cart.
Service objects are self-contained AngularJS components which we can use and reuse as we see fit. They are simple JSON objects containing functions and Data. They are always singletons, so if you store data on a service in one place, you can get that data out somewhere else just by requesting the same service.
Dependency injection (DI) vs. Instatiation - aka de-spaghettification
AngularJS manages your dependencies for you. If you want an object, simply refer to it and AngularJS will get it for you.
Until you start to use this, it's hard to explain just what a massive time boon this is. Nothing like AngularJS DI exists inside jQuery.
DI means that instead of writing your application and wiring it together, you instead define a library of components, each identified by a string.
Say I have a component called 'FlickrService' which defines methods for pulling JSON feeds from Flickr. Now, if I want to write a controller that can access Flickr, I just need to refer to the 'FlickrService' by name when I declare the controller. AngularJS will take care of instantiating the component and making it available to my controller.
For example, here I define a service:
myApp.service('FlickrService', function() {
return {
getFeed: function() { // do something here }
}
});
Now when I want to use that service I just refer to it by name like this:
myApp.controller('myController', ['FlickrService', function(FlickrService) {
FlickrService.getFeed()
}]);
AngularJS will recognise that a FlickrService object is needed to instantiate the controller, and will provide one for us.
This makes wiring things together very easy, and pretty much eliminates any tendency towards spagettification. We have a flat list of components, and AngularJS hands them to us one by one as and when we need them.
Modular service architecture
jQuery says very little about how you should organise your code. AngularJS has opinions.
AngularJS gives you modules into which you can place your code. If you're writing a script that talks to Flickr for example, you might want to create a Flickr module to wrap all your Flickr related functions in. Modules can include other modules (DI). Your main application is usually a module, and this should include all the other modules your application will depend on.
You get simple code reuse, if you want to write another application based on Flickr, you can just include the Flickr module and voila, you have access to all your Flickr related functions in your new application.
Modules contain AngularJS components. When we include a module, all the components in that module become available to us as a simple list identified by their unique strings. We can then inject those components into each other using AngularJS's dependency injection mechanism.
To sum up
AngularJS and jQuery are not enemies. It's possible to use jQuery within AngularJS very nicely. If you're using AngularJS well (templates, data-binding, $scope, directives, etc.) you will find you need a lot less jQuery than you might otherwise require.
The main thing to realise is that your template drives your application. Stop trying to write big plugins that do everything. Instead write little directives that do one thing, then write a simple template to wire them together.
Think less about unobtrusive JavaScript, and instead think in terms of HTML extensions.
My little book
I got so excited about AngularJS, I wrote a short book on it which you're very welcome to read online http://nicholasjohnson.com/angular-book/. I hope it's helpful.
Can you describe the paradigm shift that is necessary?
Imperative vs Declarative
With jQuery you tell the DOM what needs to happen, step by step. With AngularJS you describe what results you want but not how to do it. More on this here. Also, check out Mark Rajcok's answer.
How do I architect and design client-side web apps differently?
AngularJS is an entire client-side framework that uses the MVC pattern (check out their graphical representation). It greatly focuses on separation of concerns.
What is the biggest difference? What should I stop doing/using; what should I start doing/using instead?
jQuery is a library
AngularJS is a beautiful client-side framework, highly testable, that combines tons of cool stuff such as MVC, dependency injection, data binding and much more.
It focuses on separation of concerns and testing (unit testing and end-to-end testing), which facilitates test-driven development.
The best way to start is going through their awesome tutorial. You can go through the steps in a couple of hours; however, in case you want to master the concepts behind the scenes, they include a myriad of reference for further reading.
Are there any server-side considerations/restrictions?
You may use it on existing applications where you are already using pure jQuery. However, if you want to fully take advantage of the AngularJS features you may consider coding the server side using a RESTful approach.
Doing so will allow you to leverage their resource factory, which creates an abstraction of your server side RESTful API and makes server-side calls (get, save, delete, etc.) incredibly easy.
To describe the "paradigm shift", I think a short answer can suffice.
AngularJS changes the way you find elements
In jQuery, you typically use selectors to find elements, and then wire them up:
$('#id .class').click(doStuff);
In AngularJS, you use directives to mark the elements directly, to wire them up:
<a ng-click="doStuff()">
AngularJS doesn't need (or want) you to find elements using selectors - the primary difference between AngularJS's jqLite versus full-blown jQuery is that jqLite does not support selectors.
So when people say "don't include jQuery at all", it's mainly because they don't want you to use selectors; they want you to learn to use directives instead. Direct, not select!
jQuery
jQuery makes ridiculously long JavaScript commands like getElementByHerpDerp
shorter and cross-browser.
AngularJS
AngularJS allows you to make your own HTML tags/attributes that do things which work well with dynamic web applications (since HTML was designed for static pages).
Edit:
Saying "I have a jQuery background how do I think in AngularJS?" is like saying "I have an HTML background how do I think in JavaScript?" The fact that you're asking the question shows you most likely don't understand the fundamental purposes of these two resources. This is why I chose to answer the question by simply pointing out the fundamental difference rather than going through the list saying "AngularJS makes use of directives whereas jQuery uses CSS selectors to make a jQuery object which does this and that etc....". This question does not require a lengthy answer.
jQuery is a way to make programming JavaScript in the browser easier. Shorter, cross-browser commands, etc.
AngularJS extends HTML, so you don't have to put <div>
all over the place just to make an application. It makes HTML actually work for applications rather than what it was designed for, which is static, educational web pages. It accomplishes this in a roundabout way using JavaScript, but fundamentally it is an extension of HTML, not JavaScript.
jQuery: you think a lot about 'QUERYing the DOM' for DOM elements and doing something.
AngularJS: THE model is the truth, and you always think from that ANGLE.
For example, when you get data from THE server which you intend to display in some format in the DOM, in jQuery, you need to '1. FIND' where in the DOM you want to place this data, the '2. UPDATE/APPEND' it there by creating a new node or just setting its innerHTML. Then when you want to update this view, you then '3. FIND' the location and '4. UPDATE'. This cycle of find and update all done within the same context of getting and formatting data from server is gone in AngularJS.
With AngularJS you have your model (JavaScript objects you are already used to) and the value of the model tells you about the model (obviously) and about the view, and an operation on the model automatically propagates to the view, so you don't have to think about it. You will find yourself in AngularJS no longer finding things in the DOM.
To put in another way, in jQuery, you need to think about CSS selectors, that is, where is the div
or td
that has a class or attribute, etc., so that I can get their HTML or color or value, but in AngularJS, you will find yourself thinking like this: what model am I dealing with, I will set the model's value to true. You are not bothering yourself of whether the view reflecting this value is a checked box or resides in a td
element (details you would have often needed to think about in jQuery).
And with DOM manipulation in AngularJS, you find yourself adding directives and filters, which you can think of as valid HTML extensions.
One more thing you will experience in AngularJS: in jQuery you call the jQuery functions a lot, in AngularJS, AngularJS will call your functions, so AngularJS will 'tell you how to do things', but the benefits are worth it, so learning AngularJS usually means learning what AngularJS wants or the way AngularJS requires that you present your functions and it will call it accordingly. This is one of the things that makes AngularJS a framework rather than a library.
Those are some very nice, but lengthy answers.
To sum up my experiences:
- Controllers and providers (services, factories, etc.) are for modifying the data model, NOT HTML.
- HTML and directives define the layout and binding to the model.
- If you need to share data between controllers, create a service or factory - they are singletons that are shared across the application.
- If you need an HTML widget, create a directive.
- If you have some data and are now trying to update HTML... STOP! update the model, and make sure your HTML is bound to the model.
jQuery is a DOM manipulation library.
AngularJS is an MV* framework.
In fact, AngularJS is one of the few JavaScript MV* frameworks (many JavaScript MVC tools still fall under the category library).
Being a framework, it hosts your code and takes ownership of decisions about what to call and when!
AngularJS itself includes a jQuery-lite edition within it. So for some basic DOM selection/manipulation, you really don't have to include the jQuery library (it saves many bytes to run on the network.)
AngularJS has the concept of "Directives" for DOM manipulation and designing reusable UI components, so you should use it whenever you feel the need of doing DOM manipulation related stuff (directives are only place where you should write jQuery code while using AngularJS).
AngularJS involves some learning curve (more than jQuery :-).
-->For any developer coming from jQuery background, my first advice would be to "learn JavaScript as a first class language before jumping onto a rich framework like AngularJS!" I learned the above fact the hard way.
Good luck.
They're apples and oranges. You don't want to compare them. They're two different things. AngularJs has already jQuery lite built in which allows you to perform basic DOM manipulation without even including the full blown jQuery version.
jQuery is all about DOM manipulation. It solves all the cross browser pain otherwise you will have to deal with but it's not a framework that allows you to divide your app into components like AngularJS.
A nice thing about AngularJs is that it allows you to separate/isolate the DOM manipulation in the directives. There are built-in directives ready for you to use such as ng-click. You can create your own custom directives that will contain all your view logic or DOM manipulation so you don't end up mingle DOM manipulation code in the controllers or services that should take care of the business logic.
Angular breaks down your app into - Controllers - Services - Views - etc.
and there is one more thing, that's the directive. It's an attribute you can attach to any DOM element and you can go nuts with jQuery within it without worrying about your jQuery ever conflicts with AngularJs components or messes up with its architecture.
I heard from a meetup I attended, one of the founders of Angular said they worked really hard to separate out the DOM manipulation so do not try to include them back in.
Listen to the podcast JavaScript Jabber: Episode #32 that features the original creators of AngularJS: Misko Hevery & Igor Minar. They talk a lot about what it's like to come to AngularJS from other JavaScript backgrounds, especially jQuery.
One of the points made in the podcast made a lot of things click for me with respects to your question:
MISKO: [...] one of the things we thought about very hardly in Angular is, how do we provide lots of escape hatches so that you can get out and basically figure out a way out of this. So to us, the answer is this thing called “Directives”. And with directives, you essentially become a regular little jQuery JavaScript, you can do whatever you want.
IGOR: So think of directive as the instruction to the compiler that tells it whenever you come across this certain element or this CSS in the template, and you keep this kind of code and that code is in charge of the element and everything below that element in the DOM tree.
A transcript of the entire episode is available at the link provided above.
So, to directly answer your question: AngularJS is -very- opinionated and is a true MV* framework. However, you can still do all of the really cool stuff you know and love with jQuery inside of directives. It's not a matter of "How do I do what I used to in jQuery?" as much as it's a matter of "How do I supplement AngularJS with all of the stuff I used to do in jQuery?"
It's really two very different states of mind.
I find this question interesting, because my first serious exposure to JavaScript programming was Node.js and AngularJS. I never learned jQuery, and I guess that's a good thing, because I don't have to unlearn anything. In fact, I actively avoid jQuery solutions to my problems, and instead, solely look for an "AngularJS way" to solve them. So, I guess my answer to this question would essentially boil down to, "think like someone who never learned jQuery" and avoid any temptation to incorporate jQuery directly (obviously AngularJS uses it to some extent behind the scenes).
AngularJS and jQuery:
AngularJs and JQuery are completely different at every level except the JQLite functionality and you will see it once you start learning the AngularJs core features (I explained it below).
AngularJs is a client side framework that offers to build the independent client side application. JQuery is a client side library that play around the DOM.
AngularJs Cool Principle - If you want some changes on your UI think from model data change perspective. Change your data and UI will re-render itself. You need not to play around DOM each time unless and until it is hardly required and that should also be handled through Angular Directives.
To answer this question, I want to share my experience on the first enterprise application with AngularJS. These are the most awesome features that Angular provide where we start changing our jQuery mindset and we get the Angular like a framework and not the library.
Two-way data binding is amazing: I had a grid with all functionality UPDATE, DELTE, INSERT. I have a data object that binds the grid's model using ng-repeat. You only need to write a single line of simple JavaScript code for delete and insert and that's it. grid automatically updates as the grid model changes instantly. Update functionality is real time, no code for it. You feel amazing!!!
Reusable directives are super: Write directives in one place and use it throughout the application. OMG!!! I used these directive for paging, regex, validations, etc. It is really cool!
Routing is strong: It's up to your implementation how you want to use it, but it requires very few lines of code to route the request to specify HTML and controller (JavaScript)
Controllers are great: Controllers take care of their own HTML, but this separation works well for common functionality well as. If you want to call the same function on the click of a button on master HTML, just write the same function name in each controller and write individual code.
Plugins: There are many other similar features like showing an overlay in your app. You don't need to write code for it, just use an overlay plugin available as wc-overlay, and this will automatically take care of all XMLHttpRequest (XHR) requests.
Ideal for RESTful architecture: Being a complete frameworks makes AngularJS great to work with a RESTful architecture. To call REST CRUD APIs is very easier and
Services: Write common codes using services and less code in controllers. Sevices can be used to share common functionalities among the controllers.
Extensibility: Angular has extended the HTML directives using angular directives. Write expressions inside html and evaluate them on runtime. Create your own directives and services and use them in another project without any extra effort.
As a JavaScript MV* beginner and purely focusing on the application architecture (not the server/client-side matters), I would certainly recommend the following resource (which I am surprised wasn't mentioned yet): JavaScript Design Patterns, by Addy Osmani, as an introduction to different JavaScript Design Patterns. The terms used in this answer are taken from the linked document above. I'm not going to repeat what was worded really well in the accepted answer. Instead, this answer links back to the theoretical backgrounds which power AngularJS (and other libraries).
Like me, you will quickly realize that AngularJS (or Ember.js, Durandal, & other MV* frameworks for that matter) is one complex framework assembling many of the different JavaScript design patterns.
I found it easier also, to test (1) native JavaScript code and (2) smaller libraries for each one of these patterns separately before diving into one global framework. This allowed me to better understand which crucial issues a framework adresses (because you are personally faced with the problem).
For example:
- JavaScript Object-oriented Programming (this is a Google search link). It is not a library, but certainly a prerequisite to any application programming. It taught me the native implementations of the prototype, constructor, singleton & decorator patterns
- jQuery/ Underscore for the facade pattern (like WYSIWYG's for manipulating the DOM)
- Prototype.js for the prototype/ constructor/ mixin pattern
- RequireJS/ Curl.js for the module pattern/ AMD
- KnockoutJS for the observable, publish/subscribe pattern
NB: This list is not complete, nor 'the best libraries'; they just happen to be the libraries I used. These libraries also include more patterns, the ones mentioned are just their main focuses or original intents. If you feel something is missing from this list, please do mention it in the comments, and I will be glad to add it.
Actually, if you're using AngularJS, you don't need jQuery anymore. AngularJS itself has the binding and directive, which is a very good "replacement" for most things you can do with jQuery.
I usually develop mobile applications using AngularJS and Cordova. The ONLY thing from jQuery I needed is the Selector.
By googling, I see that there is a standalone jQuery selector module out there. It's Sizzle.
And I decided to make a tiny code snippet that help me quickly start a website using AngularJS with the power of jQuery Selector (using Sizzle).
I shared my code here: https://github.com/huytd/Sizzular