web-dev-qa-db-ja.com

ターボリンクでanglejsを使用する

私はアプリでAngularjsフレームワークをターボリンクで使用しようとしています。ページ変更後、新しいイベントリスナーは初期化されません。それを機能させる方法はありますか?前もって感謝します!

59
Pavel

AngularJSとTurbolinks

TurbolinksAnguluarJSの両方を使用して、ユーザーへの応答という意味で、Webアプリケーションの応答を高速化できます。インタラクションは、ページ全体を再ロードおよび再レンダリングすることなく、Webページで発生します。

次の点で異なります。

  • AngularJSは、リッチなクライアント側アプリケーションを構築するのに役立ちます、クライアントマシンで実行される多くのJavaScriptコードを記述します。このコードにより、サイトはユーザーに対してインタラクティブになります。 JSON APIを使用して、サーバー側のバックエンド、つまりRailsアプリと通信します。

  • Turbolinksは、JavaScriptをコーディングすることなくサイトをインタラクティブにするのに役立ちます。これにより、サーバー側で実行されるRuby/Railsコードにスティックを固定し、「魔法のように」AJAXを使用して置き換え、再レンダリングすることができます。 、変更されたページの部分のみ。

Turbolinksが強力なAJAXメカニズムを手で何もせずに使用し、Ruby/Railsをコーディングするだけでよい場合、JavaScriptフレームワークを統合したいアプリケーションが成長する段階が来るかもしれませんAngularJSなど。

特に、AngularJSを一度に1つのコンポーネントにアプリケーションに連続的に統合したいこの中間段階では、Angular JSとTurbolinksを一緒に実行することは完全に理にかなっています。

AngularJSとTurbolinksを一緒に使用する方法

コールバックを使用して手動でbootstrap Angular

Angularコードには、次のようなアプリケーションモジュールを定義する行があります。

# app/assets/javascripts/angular-app.js.coffee
# without turbolinks
@app = angular.module 'MyApplication', ['ngResource']

このコードは、ページがロードされるときに実行されます。ただし、Turbolinksはページの一部を置き換えるだけでページ全体の読み込みを防止するため、Turbolinksによる部分的な再読み込みの後でも、angularアプリケーションが適切に初期化(「ブートストラップ」)されるようにする必要があります。したがって、上記のモジュール宣言を次のコードに置き換えます。

# app/assets/javascripts/angular-app.js.coffee
# with turbolinks
@app = angular.module 'MyApplication', ['ngResource']

$(document).on 'turbolinks:load', ->
  angular.bootstrap document.body, ['MyApplication']

自動的にbootstrapしないでください

チュートリアルでは、HTMLコードでng-app属性を使用してbootstrapおよびAngularアプリを自動的に作成する方法をよく見ます。

<!-- app/views/layouts/my_layout.html.erb -->
<!-- without turbolinks -->
<html ng-app="YourApplication">
  ...

ただし、上記の手動bootstrapとともにこのメカニズムを使用すると、アプリケーションがbootstrapを2回実行するため、アプリケーションが停止します。

したがって、このng-app属性を削除するだけです:

<!-- app/views/layouts/my_layout.html.erb -->
<!-- with turbolinks -->
<html>
  ...

参考文献

125
fiedl

ターボリンクはページのレンダリングを最適化しようとし、AngularJSの通常のブートストラップと競合します。

アプリの一部の場所でTurbolinksを使用しており、一部の部分でAngularを使用している場合。 このエレガントなソリューション:を提案します

Angleapp(ng-app = "appname"を使用する)であるページへの各リンクには、次の属性が必要です。

<a href="/myapp" data-no-turbolink>Say NO to Turbolinks</a>.

2番目-Stackoverflowで言及されているのは、page:loadイベントを処理することにより、すべてのng-appを明示的にリロード/ブートストラップすることです。ページにないものをロードしている可能性があるため、リソースを浪費していることは言うまでもありません。

私は個人的に上記のソリューションを使用しました。

それが役に立てば幸い

9
jeveloper

バグの場合

不明なエラー:[ng:btstrpd]この要素「document」で既にブートストラップされたアプリ

angular 1.2.xへのアップグレード後、以下を使用して問題を修正できます。

_angular.module('App').run(function($compile, $rootScope, $document) {
  return $document.on('page:load', function() {
    var body, compiled;
    body = angular.element('body');
    compiled = $compile(body.html())($rootScope);
    return body.html(compiled);
  });
});
_

以前の投稿で@natesはangular.bootstrap(document, ['YourApplication'])angular.bootstrap("body", ['YourApplication'])に変更することを提案しましたが、これはコンパイルされていないコンテンツのフラッシュを引き起こします。

4
Artur Trzop

jquery.turbolinks プラグインは、ng-appディレクティブを介してモジュールのブートストラップをトリガーできます。手動でモジュールをbootstrap=)しようとすると、jquery.turbolinksはng:btstrpdエラーにつながる可能性があります。jquery.turbolinksはpage:loadこれは、新しいページ固有の<script>タグの実行が完了する前にトリガーできるイベントです。application.jsの外部でモジュール定義を含めると、$injector:nomodエラーが発生する可能性があります。特定のページにのみ含まれる個別のjavascriptファイルは、data-no-turbolinkを介して特定のページへのリンクで ターボリンクを無効にする にすることができます。

1

次のイベントハンドラーをアプリケーションに追加します。

Coffeescript:

bootstrapAngular = ->
  $('[ng-app]').each ->
    module = $(this).attr('ng-app')
    angular.bootstrap(this, [module])

$(document).on('page:load', bootstrapAngular)

Javascript:

function bootstrapAngular() {
  $('[ng-app]').each(function() {
    var module = $(this).attr('ng-app');
    angular.bootstrap(this, [module]);
  });
};
$(document).on('page:load', bootstrapAngular);

これにより、angularアプリケーションがTurbolinksによって各ページがロードされた後に開始されます。

https://Gist.github.com/ayamomiji/4736614 へのクレジット

1
Robin Daugherty

Turbolinksは、クライアント側のMVCフレームワークではあまり意味がありません。 Turbolinksは、サーバーの応答から本文を除くすべてを取り除くために使用されます。クライアント側のMVCでは、HTMLではなくJSONをクライアントに渡すだけです。

いずれにしても、ターボリンクは独自のコールバックを作成します。

page:load
page:fetch
page:restore
page:change
1
cpuguy83

TurbolinksとAngularJSを一緒に使用する

すばらしい回答を得るには、@ fiedlに+1してください。しかし、私の好みはpage:changepage:loadこれはある程度の柔軟性を提供するためです。DOMはpage:loadターボリンク以外のソースからのイベントなので、同じコールバックを起動したくない場合があります。

page:changeその後 a page:loadは、コールバックの動作を、ターボリンクによって引き起こされたイベントのみに制限する必要があります。

function boostrapAngularJS () {
    angular.bootstrap(document.body, ['My Application']);
    addCallbackToPageChange();
}
function addCallbackToPageChange() {
    angular.element(document).one('page:change', function () {
        angular.element(this).one('page:load', boostrapAngularJS);
    });
}
addCallbackToPageChange();

(これにより、ng-app html内の宣言。AngularJSを使用する場合は通常どおり。

0
JellicleCat

Turbolinksは自動的にページを取得し、その<body>にスワップし、<head>をマージします。すべてのページをロードするコストは発生しません。

https://github.com/turbolinks/turbolinks#turbolinks

そのため、ng-app要素に<html>ディレクティブを追加する代わりに、<body>要素に追加できます。

<html>
  <body ng-app=“yourApplicationModuleName">
  </body>
</html>
0
Repolês

私が見たコメントに基づいて、AngularがTurbolinksと競合するような方法で両方を一緒に使用するための唯一の有効なシナリオ(たとえば、Angular =ルーティングの一部を処理するため)は、Angularに移植しようとしている既存のアプリケーションがある場合です。

個人的に、これをゼロから行う場合、最善の解決策はルーティングを処理するものを決定し、それに従うことだと思います。 Angularの場合、Turbolinksを削除するよりも、シングルページアプリに近いものがあれば、それはあまり役に立ちません。 Rails=ルーティングの処理を許可する場合は、Angular=を使用して、サーバーで処理できないクライアント側の動作を整理します。テンプレート。

ここにシナリオがありませんか?大規模なアプリケーションであっても、異なるフレームワーク間でルーティングの責任を分割しようとするのはエレガントではないようです... TurbolinksがAngular更新以外に干渉する他のシナリオはありますかページまたは新しいルートに移動しますか?

0
josiah