stateprovider stateparams start route example change javascript model angularjs state

javascript - stateparams - ng-model angularjs



Dónde debe almacenarse el estado del modelo en Angular.js (3)

Estoy descubriendo que el uso de Angular de los modelos es confuso. Angular parece adoptar el enfoque de que un modelo puede ser lo que más te guste: IE Angular no incluye una clase de modelo explícita y puedes usar objetos de JavaScript de vanilla como modelos.

En casi todos los ejemplos de Angular que he visto, el modelo es efectivamente un objeto, ya sea creado a mano, o devuelto de una llamada API a través de un recurso. Como casi todos los ejemplos angulares que he analizado son simples, generalmente los datos del modelo almacenados en $ scope en un controlador y cualquier estado relacionado con el modelo, por ejemplo, la selección, también se almacena en $ scope en el controlador. Esto funciona bien para aplicaciones / ejemplos simples, pero esto parece una simplificación excesiva cuando las aplicaciones se vuelven más complejas. El estado del modelo almacenado en un controlador corre el riesgo de convertirse en contexto y perderse si el contexto cambia, por ejemplo; Un controlador que almacena la galería selectedGallery y la selectedPhoto solo pueden almacenar una imagen selectedImage global, no una selectedPhoto por galería. En tal situación, usar un controlador por galería podría negar este problema, pero parecería un desperdicio y probablemente inapropiado e innecesario desde la perspectiva de la interfaz de usuario.

La definición de modelos de Angular parece más cercana a lo que yo consideraría un VO / DTO que es un objeto tonto pasado entre el servidor y el cliente. Mi instinto es envolver dicho objeto en lo que yo consideraría un Modelo - una clase que mantiene el estado relacionado con el DTO / VO (como la selección), ofrece mutadores según sea necesario para manipular el DTO / VO, y notifica al resto del aplicación de cambios a los datos subyacentes. Obviamente, esta última parte está muy bien cuidada por las ataduras de Angular, pero todavía veo un fuerte caso de uso para las dos primeras responsabilidades.

Sin embargo, no he visto realmente este patrón utilizado en los ejemplos que he analizado, pero tampoco he visto lo que consideraría una alternativa escalable. Angular parece desaconsejar implícitamente el uso de los Servicios como modelos mediante la aplicación de Singletons (sé que hay formas de evitar esto, pero no parecen ser ampliamente utilizados o aprobados).

Entonces, ¿cómo debería mantener el estado en los datos del modelo?

[Editar] La segunda respuesta en esta pregunta es interesante y cercana a lo que estoy usando actualmente.


Estado (y modelos) se almacenan en $ scope

$ scope es el objeto de almacenamiento de datos de Angular. Es análogo a una base de datos. $ scope en sí mismo no es el modelo, pero puede almacenar modelos en $ scope.

Cada $ scope tiene un $ $ scope, hasta $ rootScope formando una estructura de árbol que refleja ligeramente su DOM. Cuando llama a una directiva que requiere un nuevo $ scope, como ng-controller, se creará un nuevo objeto $ scope y se agregará al árbol.

$ objetos de alcance están conectados usando herencia prototípica. Esto significa que si agrega un modelo a un nivel superior en el árbol, estará disponible para todos los niveles inferiores. Esta es una característica fenomenalmente poderosa que hace que la jerarquía $ scope sea casi transparente para el autor de la plantilla.

Los controladores inicializan $ scope

El propósito del controlador es inicializar $ scope . El mismo controlador puede inicializar muchos objetos $ scope en diferentes partes de la página. El controlador se crea una instancia, configura el objeto $ scope y luego sale. Puede usar el mismo controlador para inicializar muchos $ scopes en diferentes partes de la página.

En el caso de su galería de imágenes, tendría un controlador imageGallery que luego aplicaría a cada parte del DOM que desea que sea una galería utilizando la directiva ng-controller. Esa parte de la página obtendría su propio $ scope, que usaría para almacenar el atributo selectedPhoto.

Alcances prototípicos

$ scope hereda de su padre el uso de herencia prototípica simple hasta $ rootScope, por lo que puede almacenar sus objetos en cualquier lugar de la jerarquía que tenga sentido. Obtienes un árbol de objetos $ scope que aproximadamente se relaciona con tu DOM actual. Si su DOM cambia, se crean nuevos objetos $ scope según sea necesario.

$ scope es solo un objeto JavaScript sin formato. No es más derrochador crear múltiples objetos $ scope de lo que sería crear una matriz con múltiples objetos de imagen actual. Es una forma sensata de organizar tu código.

De esta forma, Angular elimina el viejo problema de "dónde guardo mis datos" que a menudo encontramos en JavaScript. Es la fuente de una de las ganancias de productividad realmente grandes que obtenemos de Angular.

¿Tienes datos globales (por ejemplo, un ID de usuario)? guárdelo en $ rootScope. ¿Tiene datos locales (por ejemplo, una imagen actual en una galería donde hay varias instancias de galería)? Guárdelo en el objeto $ scope que pertenece a esa galería.

$ scope está automáticamente disponible para usted en la parte correcta de la plantilla.

Los modelos angulares son delgados

Viniendo de un fondo de Rails donde destacamos los modelos gordos y los controladores delgados, encontré sorprendentes los modelos "apenas disponibles" de Angular. De hecho, poner mucha lógica comercial en su modelo a menudo conduce a problemas en el futuro, como a veces vemos con el modelo de Usuario en Rails que, si no tiene cuidado, crecerá hasta que se vuelva imposible de mantener.

Un modelo angular es simplemente un objeto JavaScript o primitivo.

Cualquier objeto puede ser un modelo. Los modelos generalmente se definen usando JSON en el controlador o AJAX desde un servidor. Un modelo podría ser un objeto JSON, o podría ser solo una cadena, matriz o incluso un número.

Por supuesto, no hay nada que le impida agregar funciones adicionales a su modelo y almacenarlas en el objeto JSON si así lo desea, pero esto sería portar en un paradigma que realmente no se ajusta a Angular.

Los objetos angulares suelen ser repositorios de datos, no de funciones.

El modelo en la parte delantera no es el modelo real

Por supuesto, el modelo que tienes sobre el cliente no es el modelo real. Su modelo real, su única fuente de verdad vive en el servidor. Lo sincronizamos usando una API, pero si hay un conflicto entre los dos, el modelo en su base de datos es obviamente el vencedor final.

Esto le da privacidad para cosas como códigos de descuento, etc. El modelo que encuentra en su interfaz es una versión sincronizada de las propiedades públicas del modelo real, que es remoto.

La lógica de negocios puede vivir en servicios.

Digamos que quiere escribir un método para hacer algo con su modelo, sincronizarlo o validarlo, por ejemplo. En otros marcos, es posible que tengas la tentación de extender tu modelo con un método para hacerlo. En Angular, es más probable que escribas un servicio.

Los servicios son objetos únicos. Al igual que cualquier otro objeto JavaScript, puede poner funciones o datos en ellos. Angular viene con un conjunto de servicios integrados, como $ http. Puede construir el suyo propio y usar la inyección de dependencia para proporcionarlos automáticamente a sus controladores.

Un servicio puede contener métodos para hablar con una API RESTful, por ejemplo, o para validar sus datos, o cualquier otro trabajo que pueda necesitar hacer.

Los servicios no son modelos

Por supuesto, no deberías usar servicios como modelos. Úselos como objetos que pueden hacer cosas. A veces hacen cosas a tu modelo. Es una forma diferente de pensar, pero viable.


Angular no tiene una opinión sobre cómo almacenar lo que usted llama "objetos modelo". El $scope controlador angular existe únicamente como un "modelo de vista" para los propósitos de administrar su UI. Sugiero separar estos dos conceptos en tu código.

Si desea la precisión de la notificación de cambio de alcance angular ( $watch ), puede usar un objeto de alcance para almacenar los datos de su modelo si lo desea ( var myScope = $rootScope.$new() ). Simplemente no use el mismo objeto de alcance al que está vinculada su UI.

Recomiendo escribir servicios personalizados para este fin. Entonces, el flujo de datos es así:

AJAX -> Servicio personalizado -> Objeto del alcance del modelo -> Controlador -> Objeto del alcance de la interfaz de usuario -> DOM

O esto:

AJAX -> Servicios personalizados -> Objetos de JavaScript antiguos simples -> Controlador -> Objeto de alcance de UI -> DOM


Antes que nada, no olvidemos que Angular es un framework basado en web y si "mantiene su estado" únicamente en un objeto, no sobrevivirá al usuario al actualizar en su navegador. Por lo tanto, averiguar cómo mantener el estado de los datos del modelo en una aplicación basada en web significa descubrir cómo va a persistir para que su código funcione en un entorno de navegador.

Angular hace que sea muy fácil para usted persistir en su estado usando:

  1. Una llamada a un recurso RESTful $
  2. Una URL que representa una instancia de su modelo

En su ejemplo simple, el almacenamiento de las acciones del usuario como selectedGallery y selectedPhoto se puede representar mediante URL con algo como:

// List of galleries .../gallery // List of photos in a gallery .../gallery/23 // A specific photo .../gallery/23/photo/2

La URL es crítica porque permite a su usuario navegar por el historial del navegador usando los botones back y forward . Si desea compartir este estado con otra parte de su aplicación, la aplicación web le brinda una gran variedad de métodos para lograrlo al usar cookies / localStorage, marcos / campos ocultos o incluso almacenarlos en su servidor.

Una vez que haya definido su estrategia sobre cómo persistir el estado diferente de su aplicación, será más fácil decidir si desea acceder a esta información persistente utilizando un objeto singleton proporcionado por .service o una instancia a través de .factory .