playframework knockout.js angularjs dust.js

playframework - Plantilla HTML completada en el lado del servidor y actualizada en el lado del cliente



knockout.js angularjs (4)

Una opción en AngularJS podría ser utilizar una directiva que copie los valores representados en el servidor en el modelo y que las acciones posteriores recuperen datos a través de JavaScript.

He utilizado el método descrito aquí en una aplicación ASP.NET WebForms para rellenar previamente mi modelo a través de valores ocultos del servidor en la primera solicitud. Según la discusión, esto se rompe de la manera angular, pero es posible.

Aquí hay un ejemplo del html:

<input type="hidden" ng-model="modelToCopyTo" copy-to-model value=''"this was set server side"'' />

JavaScript:

var directiveModule = angular.module(''customDirectives'', []); directiveModule.directive(''copyToModel'', function ($parse) { return function (scope, element, attrs) { $parse(attrs.ngModel).assign(scope, JSON.parse(attrs.value)); } });

Tengo una página web con contenido dinámico. Digamos que es una página de producto. Cuando el usuario vaya directamente a example.com/product/123 , quiero presentar mi plantilla de producto en el servidor y enviar html al navegador. Sin embargo, cuando el usuario luego hace clic en un enlace a /product/555 me gustaría usar JavaScript para actualizar la plantilla en el lado del cliente.

Me gustaría utilizar algo como Knockout.js o Angularjs, pero no veo cómo puedo completar previamente esas plantillas con algunos datos iniciales en el servidor y todavía tener una plantilla en funcionamiento en el cliente. es decir, si mi plantilla angular es esta:

<ul> <li ng-repeat="feature in features"> {{feature.title}} <p>{{feature.description}}</p> </li> </ul>

Cuando el usuario va directamente a la URL, necesito algo que aún funcione como una plantilla angular, pero se rellena con el html para el producto actual. Obviamente esto no funciona:

<ul> <li ng-repeat="feature in features">Hello <p>This feature was rendered server-side</p> </li> <li>Asdf <p>These are stuck here now since angular won''t replace them when it updates.... </p></li> </ul>

Parece que mi única opción es enviar el html procesado por el servidor al navegador junto con una plantilla de coincidencia por separado ...

En ese caso, me gustaría evitar escribir cada plantilla dos veces. Lo que significa que necesito cambiar a JavaScript para el idioma de mi servidor (que no me gustaría) o elegir un lenguaje de plantilla que se compile tanto para Java como para JavaScript y luego encontrar la forma de hackearlo en Play Framework (que es lo que Actualmente estoy usando.)

¿Alguien tiene algún consejo?


No sé de un buen techiqunue para hacer esto, pero esto es algo que me he decidido por el momento en una aplicación de rieles que estoy construyendo.

Empieza por inicializar su plantilla con datos de inicialización usando ng-init .

<ul ng-init="features = <%= features.to_json %>"> <li ng-repeat="feature in features"> {{feature.title}} <p>{{feature.description}}</p> </li> </ul>

Luego renderizas los datos de semilla dos veces. Una vez desde el servidor y una vez más, Angular ha iniciado su aplicación. Cuando la aplicación se inicializa, Angular ocultará los datos de inicialización dejando solo la plantilla angulada.

Es importante que use ng-cloak para ocultar la plantilla angular antes de que se arranque.

<ul ng-hide="true"> <% features.each do |feature| %> <li> <%= feature.title %> <p><%= feature.description =></p> </li> <% end %> </ul> <ul ng-hide="false" ng-cloak ng-init="features = <%= features.to_json %>"> <li ng-repeat="feature in features"> {{feature.title}} <p>{{feature.description}}</p> </li> </ul>

No se escala con plantillas grandes, está duplicando el marcado, pero al menos no obtendrá ese parpadeo mientras Angular está iniciando su aplicación.

Idealmente, me gustaría poder volver a utilizar la misma plantilla en el servidor que en el cliente. Algo como el bigote viene a la mente. Obviamente, el truco sería implementar las directivas de angular y el control de flujo. No es un trabajo fácil.


Si realmente desea tener un valor inicial almacenado en un área antes de que Angular se active, puede usar el atributo ng-bind en lugar de {{bound strings}}, de su ejemplo:

<ul> <li ng-repeat="feature in features"> <div ng-bind="feature.title">Hello</div> <p ng-bind="feature.description">This feature was rendered server-side but can be updated once angular activates</p> </li> </ul>

No estoy seguro de dónde esto podría ser útil, pero también querrá incluir el conjunto de datos inicial como parte de una etiqueta de secuencia de comandos en el documento, de modo que cuando se active ANGULAR no se borre la información mostrada con nulos.

Editar: (Según lo solicitado por los comentaristas)

Alternativamente, puede hacer una repetición ng en la parte superior de la lista, configurarla para que se complete en función de la lista de "características". Siguiendo ese elemento ng-repeat, tienen elementos non-ng-repeat que tienen un atributo ng-hide con la configuración ng-hide = "features", si Angular carga, todos los elementos de la lista proporcionada por el servidor original se ocultan, y la lista angular salta a la existencia. Sin modificaciones hacky a angular, y sin tocar el atributo directo ng-bind.

Como nota al margen, es posible que desee enviar una secuencia de comandos capaz de leer ese elemento servidor inicial para sus datos para alimentarlo en angular antes de sincronizar angular si desea evitar un parpadeo donde angular borra los datos mientras espera un solicitar los mismos datos del servidor.


Solo he usado Knockout, no Angular, pero un enfoque aparentemente muy común que uso es tener el estado inicial de tus datos representados en el marcado de la página como JSON, y en DOM ready usar eso para construir tu modelo de vista Javascript inicial, luego aplica los enlaces Knockout para construir la UI. De modo que la interfaz de usuario se construye desde el lado del cliente incluso para un elemento como el producto que ya existe en el servidor. Esto significa que se pueden invocar las mismas plantillas tanto para la creación de la interfaz de usuario inicial como para agregar algo del lado del cliente, como un subproducto con su propio modelo y plantilla. Es ésta una opción para usted?

Editar: en caso de que malinterprete sus requisitos, el enfoque del que estoy hablando se detalla más en esta pregunta: KnockoutJS duplicación de datos de arriba