13

動的コンテンツを含むWebページがあります。製品ページだとしましょう。ユーザーが直接アクセスしたときexample.com/product/123に、サーバー上で製品テンプレートをレンダリングし、ブラウザーにhtmlを送信したいと思います。ただし、ユーザーが後でリンクをクリックしたときに、/product/555JavaScriptを使用してクライアント側のテンプレートを更新したいと思います。

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を別の一致するテンプレートと一緒にブラウザに送信することだと思われます...?

その場合、すべてのテンプレートを2回書くことは避けたいと思います。つまり、サーバー言語をJavaScriptに切り替えるか(これについては満足できません)、JavaとJavaScriptの両方にコンパイルできるテンプレート言語を選択してから、それをPlay Frameworkにハックする方法を見つける必要があります(これが現在使用しています。)

誰かアドバイスはありますか?

4

4 に答える 4

7

Angularがアクティブ化される前に初期値を領域に格納したい場合は、例の{{boundstrings}}ではなくng-bind属性を使用できます。

<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がアクティブ化されたときに表示された情報が消去されないように、スクリプトタグの一部として初期データセットをドキュメントに含めることもできます。 nullを使用します。

編集:(コメント投稿者の要求に応じて)

または、リストの一番上にng-repeatを作成し、「機能」リスト自体に基づいて入力するように構成することもできます。そのng-repeat要素に続いて、ng-hide = "features"の設定でng-hide属性を持つ非ng-repeat要素があり、Angularが読み込まれると、元のサーバー提供リストのすべての要素が非表示になり、角度リストが存在し始めます。Angularにハッキーな変更を加えたり、直接ng-bind属性をいじったりすることはありません。

補足として、Angularが待機中にデータをクリアする点滅を回避したい場合は、Angularが同期する前に、データの最初のサーバー要素を読み取ってAngularにフィードできるスクリプトを送信することをお勧めします。サーバーから同じデータを要求します。

于 2012-08-07T04:41:31.343 に答える
2

私はAngularではなくKnockoutのみを使用しましたが、私が使用する非常に一般的なアプローチは、データの初期状態をJSONとしてページマークアップにレンダリングすることです。DOMでは、これを使用して初期Javascriptビューモデルを構築します。次に、ノックアウトバインディングを適用してUIを構築します。そのため、サーバー上にすでに存在する製品などのアイテムに対しても、UIはクライアント側で構築されます。つまり、最初のUI作成と、独自のビューモデルとテンプレートを持つサブ製品などのクライアント側を追加する場合の両方で、まったく同じテンプレートを呼び出すことができます。これはあなたにとっての選択肢ですか?

編集:私があなたの要件を誤解した場合に備えて、私が話しているアプローチは、この質問でより詳細に説明されています:データオーバーヘッドを複製するKnockoutJS

于 2012-08-07T04:26:24.900 に答える
1

AngularJSの1つのオプションは、サーバーでレンダリングされた値をモデルにコピーし、後続のアクションで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>

次に、シードデータを2回レンダリングします。サーバーから1回、Angularがアプリケーションをブートストラップした後。アプリケーションがブートストラップされると、Angularは初期シードデータを非表示にし、Angular化されたテンプレートのみを残します。

ブートストラップする前に、 ng-cloakを使用してAngularテンプレートを非表示にすることが重要です。

<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 に答える