13

我有一个包含动态内容的网页。假设它是一个产品页面。当用户直接访问时,example.com/product/123我想在服务器上呈现我的产品模板并将 html 发送到浏览器。但是,当用户稍后单击指向/product/555我想使用 JavaScript 更新客户端上的模板的链接时。

我想使用 Knockout.js 或 Angularjs 之类的东西,但我不知道如何在服务器上使用一些初始数据预先填充这些模板,并且在客户端上仍然有一个正常工作的模板。即如果我的 Angular 模板是这样的:

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

当用户直接访问 URL 时,我需要一些仍可用作 Angular 模板的东西,但填充了当前产品的 html。显然这不起作用:

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

似乎我唯一的选择是将服务器呈现的 html 与单独的匹配模板一起发送到浏览器......?

在这种情况下,我想避免每个模板都写两次。这意味着我需要为我的服务器语言切换到 JavaScript(我不会对此感到高兴),或者选择一种同时编译为 Java 和 JavaScript 的模板语言,然后找到一种方法将其破解到 Play 框架中(这就是我目前正在使用。)

有人有建议吗?

4

4 回答 4

7

如果您真的想在 Angular 激活之前将初始值存储在某个区域中 - 您可以使用 ng-bind 属性而不是 {{bound strings}},从您的示例中:

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

我不确定这会在哪里派上用场,但您还需要将初始数据集作为脚本标签的一部分包含在文档中,这样当 angular DOES 激活时,它不会清除显示的信息带空值。

编辑:(根据评论者的要求)

或者,您可以在列表顶部创建一个 ng-repeat,将其配置为根据“功能”列表本身进行填写。在该 ng-repeat 元素之后,具有具有设置 ng-hide="features" 的 ng-hide 属性的非 ng-repeat 元素,如果加载了 Angular,则原始服务器提供的列表中的所有元素都会隐藏自己,并且角度列表开始存在。没有对 Angular 进行任何修改,也没有摆弄直接 ng-bind 属性。

作为旁注,您可能仍然希望发送一段脚本,该脚本能够读取该初始服务器元素的数据,以便在角度同步之前将其馈入角度,如果您想避免在等待角度时清除数据的眨眼从服务器请求相同的数据。

于 2012-08-07T04:41:31.343 回答
2

我只使用了 Knockout,而不是 Angular,但我使用的一种看似非常常见的方法是将数据的初始状态作为 JSON 呈现到页面标记中,并在 DOM 上准备好使用它来构建您的初始 Javascript 视图模型,然后应用 Knockout 绑定来构建 UI。因此,即使对于已经存在于服务器上的产品(例如您的产品),UI 也会构建客户端。这意味着可以在初始 UI 创建和添加客户端时调用相同的模板,例如具有自己的视图模型和模板的子产品。这是您的选择吗?

编辑:如果我误解了您的要求,我正在谈论的方法在这个问题中有更详细的说明:KnockoutJS 复制数据开销

于 2012-08-07T04:26:24.900 回答
1

AngularJS 中的一个选项可能是使用指令将服务器上呈现的值复制到模型中,并让后续操作通过 JavaScript 检索数据。

我在 ASP.NET WebForms 应用程序中使用此处描述的方法,在第一次请求时通过来自服务器的隐藏值预填充我的模型。根据讨论,这与 Angular 方式不同,但这是可能的。

这是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));
    }
});
于 2012-08-07T04:26:47.123 回答
0

我不知道这样做有什么好的技术,但这是我暂时在我正在构建的 Rails 应用程序中确定的东西。

您首先使用ng-init使用种子数据初始化模板。

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

然后你渲染种子数据两次。一次来自服务器,一次 Angular 引导您的应用程序。当应用程序启动时,Angular 将隐藏初始种子数据,只留下角度化的模板。

在引导之前使用ng-cloak隐藏角度模板很重要。

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

它不适用于大型模板,您正在复制标记,但至少在 Angular 引导您的应用程序时不会出现闪烁。

理想情况下,我希望能够在服务器上重复使用与客户端相同的模板。像小胡子这样的东西浮现在脑海中。显然,诀窍是实现 angular 的指令和流控制。不是一件容易的工作。

于 2013-04-10T02:32:40.700 回答