HTML template filled in server-side and updated client-side

為{幸葍}努か 提交于 2019-11-27 11:44:29

问题


I have a webpage with dynamic content. Let's say it's a product page. When the user goes directly to example.com/product/123 I want to render my product template on the server and send html to the browser. However, when the user later clicks a link to /product/555 I'd like to use JavaScript to update the template on the client-side.

I'd like to use something like Knockout.js or Angularjs, but I don't see how I can pre-populate those templates with some initial data on the server and still have a functioning template on the client. i.e. If my Angular template is this:

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

When the user goes directly to the URL, I need something that still works as an Angular template, but is filled in with the html for the current product. Obviously this doesn't work:

<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>

It seems like my only option is to send the server-rendered html to the browser along with a separate matching template...?

In that case, I'd like to avoid writing every template twice. Which means I need to either switch to JavaScript for my server language (which I would not be happy about) or choose a template language that compiles to both Java and JavaScript and then find a way to hack it into the Play Framework (which is what I'm currently using.)

Does anyone have any advice?


回答1:


If you would really like to have an initial value stored in an area before Angular activates- you can use the ng-bind attribute rather than {{bound strings}}, from your example:

<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>

I'm not sure where this would come in handy, but you'll also want to include the initial data-set as part of a script tag in the document, so that when angular DOES activate it doesn't wipe out the displayed information with nulls.

Edit: (As requested by commenters)

Alternatively, you could make an ng-repeat at the top of the list, have it configured to fill out based on the 'features' list itself. Following that ng-repeat element, have non-ng-repeat elements which have an ng-hide attribute with the setting ng-hide="features", if Angular loads, all the elements from the original server-provided list hide themselves, and the angular list jumps into existence. No hacky modifications to Angular, and no fiddling with the direct ng-bind attribute.

As a side note, you might still want to send a piece of script capable of reading that initial server-element for its data to feed it into angular before angular synchronizes if you want to avoid a blink where angular clears the data while waiting for a request for the same data from the server.




回答2:


I've only used Knockout, not Angular, but a seemingly very common approach which I use is to have the initial state of your data rendered into the page markup as JSON, and on DOM ready use that to build your initial Javascript view model, then apply the Knockout bindings to build the UI. So the UI gets built client side even for an item such as your product which already exists on the server. This means the very same templates can be invoked both for the initial UI creation and when you add something client side, like a sub-product with its own view model and template. Is this an option for you?

Edit: in case I misunderstood your requirements, the approach I'm talking about is detailed more in this question: KnockoutJS duplicating data overhead




回答3:


One option in AngularJS might be to use a directive that copies values rendered on the server into the model and have subsequent actions retrieve data via JavaScript.

I've used the method described here in an ASP.NET WebForms application to pre-populate my model via hidden values from the server on the first request. Per the discussion this breaks from the Angular way but it is possible.

Here is example of the 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));
    }
});



回答4:


I don't know of a nice techiqunue for doing this, but this is something I've settled on for the time being in a rails application I'm building.

You start by initialising your template with seed data using ng-init.

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

Then you render the seed data twice. Once from the server and again once Angular has bootstrapped your application. When the application is bootstrapped, Angular will hide the initial seed data leaving only the angularized template.

It's important that you use ng-cloak to hide the angular template before it's bootstrapped.

<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>

It doesn't scale with large templates, you're duplicating markup, but at least you won't get that flickering while Angular is bootstrapping your app.

Ideally I'd like to be able to re-use the same template on the server as on the client. Something like mustache comes to mind. Obviously the trick would be implementing angular's directives and flow control. Not an easy job.



来源:https://stackoverflow.com/questions/11838639/html-template-filled-in-server-side-and-updated-client-side

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!