アプリでターボリンクを使用してAngularjsフレームワークを使用しようとしています。ページ変更後、新しいイベントリスナーは初期化されません。それを機能させる方法はありますか?前もって感謝します!
9 に答える
AngularJSとTurbolinks
TurbolinksとAnguluarJSはどちらも、ユーザーの操作に応答してページ全体をリロードおよび再レンダリングせずにWebページで何かが発生するという意味で、Webアプリケーションの応答を高速化するために使用できます。
それらは次の点で異なります。
AngularJSは、クライアントマシンで実行される多くのJavaScriptコードを記述した、リッチなクライアント側アプリケーションの構築に役立ちます。このコードは、サイトをユーザーにとってインタラクティブにします。JSON APIを使用して、サーバー側のバックエンド、つまりRailsアプリと通信します。
一方、Turbolinksは、JavaScriptをコーディングしなくても、サイトをインタラクティブにするのに役立ちます。これにより、サーバー側で実行されるRuby / Railsコードに固執し、「魔法のように」AJAXを使用して、変更されたページの部分のみを置き換え、再レンダリングすることができます。
Turbolinksがこの強力なAJAXメカニズムを手作業で何もせずに、Ruby / Railsをコーディングするだけで使用できるようにすることに強い場合、アプリケーションが成長するにつれて、AngularJSなどのJavaScriptフレームワークを統合したい段階が来るかもしれません。
特に、AngularJSをアプリケーションに一度に1つのコンポーネントで連続的に統合したいこの中間段階では、AngularJSとTurbolinksを一緒に実行することは完全に理にかなっています。
AngularJSとTurbolinksを一緒に使用する方法
コールバックを使用して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']
自動的にブートストラップしないでください
チュートリアルng-app
では、HTMLコードの属性を使用してAngularアプリを自動的にブートストラップする方法をよく目にします。
<!-- app/views/layouts/my_layout.html.erb -->
<!-- without turbolinks -->
<html ng-app="YourApplication">
...
ただし、このメカニズムを上記の手動ブートストラップと一緒に使用すると、アプリケーションが2回ブートストラップされるため、アプリケーションにブレーキがかかります。
したがって、このng-app
属性を削除するだけです。
<!-- app/views/layouts/my_layout.html.erb -->
<!-- with turbolinks -->
<html>
...
参考文献
- AngularJSブートストラップ: http: //docs.angularjs.org/guide/bootstrap
- TurbolinksのRailscasts(コールバックについて説明しています): http: //railscasts.com/episodes/390-turbolinks
- デモアプリケーション:https ://github.com/fiedl/rails-5-angular-and-turbolinks-demo
Turbolinksはページのレンダリングを最適化しようとし、AngularJSの通常のブートストラップと競合します。
アプリの一部の場所でTurbolinksを使用していて、一部の部分でAngularを使用している場合。私はこのエレガントなソリューションを提案します:
angleapp(ng-app = "appname"を使用する)であるページへの各リンクには、次の属性が必要です。
<a href="/myapp" data-no-turbolink>Say NO to Turbolinks</a>.
2番目-Stackoverflowで言及されているのは、page:loadイベントを処理することにより、すべてのng-appを明示的にリロード/ブートストラップすることです。ページにないものをロードしている可能性があることは言うまでもなく、それは煩わしいことであり、したがってリソースを浪費します。
私は個人的に上記の解決策を使用しました。
それが役に立てば幸い
バグの場合
キャッチされないエラー:[ng:btstrpd]アプリはすでにこの要素でブートストラップされています'ドキュメント'
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'])
たが、これにより、コンパイルされていないコンテンツがフラッシュされます。
次のイベントハンドラーをアプリケーションに追加します。
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);
これにより、Turbolinksによって各ページが読み込まれた後にAngularアプリケーションが開始されます。
Turbolinksは、クライアント側のMVCフレームワークではまったく意味がありません。Turbolinksは、サーバーの応答から本体以外のすべてを取り除くために使用されます。クライアント側のMVCでは、HTMLではなくJSONをクライアントに渡す必要があります。
いずれにせよ、turbolinksは独自のコールバックを作成します。
page:load
page:fetch
page:restore
page:change
jquery.turbolinksプラグインは、ng-appディレクティブを介してモジュールのブートストラップをトリガーできます。モジュールを手動でブートストラップしようとしている場合、jquery.turbolinksはng:btstrpdエラーを引き起こす可能性があります。私が見つけた注意点の1つは、jquery.turbolinksがpage:load
イベントに依存していることです。このイベントは、新しいページ固有の<script>
タグの実行が終了する前にトリガーされる可能性があります。$injector:nomod
application.jsの外部にモジュール定義を含めると、エラーが発生する可能性があります。特定のページにのみ含まれる個別のJavaScriptファイルでモジュールを定義する必要がある場合は、を介してそれらの特定のページへのリンクでターボリンクを無効data-no-turbolink
にすることができます。
私が見たコメントに基づくと、AngularがTurbolinksと競合する方法で両方を一緒に使用するための唯一の有効なシナリオ(Angularにルーティングの一部を処理させる場合など)は、既存のアプリケーションがある場合です。 mAngularに移植しようとしています。
個人的に、これを最初から行う場合、最善の解決策は、ルーティングを処理するものを決定し、それに固執することだと思います。Angularの場合、Turbolinksを削除するよりも->単一ページのアプリに近いものがある場合は、あまり効果がありません。Railsにルーティングの処理を許可する場合は、Angularを使用して、テンプレートを提供するときにサーバーで処理できないクライアント側の動作を整理します。
ここでシナリオが欠落していますか?大規模なアプリケーションであっても、ルーティングの責任を異なるフレームワーク間で分割しようとするのは私にはエレガントではないようです...ページの更新や新しいルートへの移動以外にTurbolinksがAngularに干渉するシナリオは他にありますか?
TurbolinksとAngularJSを一緒に使用する
素晴らしい答えを得るには@fiedlに+1してください。しかし、私の好みは、これがある程度の柔軟性を提供するためpage:change
、協調して利用することです。DOMはターボリンク以外のソースからイベントをpage:load
受信できるため、同じコールバックを起動したくない場合があります。page:load
を監視しpage:change
、次に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
(これにより、AngularJSを使用する場合の通常のように、宣言をhtmlに保持することができます/必要になります。)
Turbolinksは、ページを自動的にフェッチし、そのページをスワップインし、そのページ
<body>
をマージし<head>
ます。これらはすべて、ページ全体の読み込みのコストを発生させることなく行われます。
https://github.com/turbolinks/turbolinks#turbolinks
したがって、要素にng-app
ディレクティブを追加する代わりに、<html>
要素に対してそれを行うことができます<body>
。
<html>
<body ng-app=“yourApplicationModuleName">
</body>
</html>