Ruby on Rails-在TurboLinks中使用angularjs

我试图在我的应用程序中通过turbolinks使用Angularjs框架。 页面更改后,请勿初始化新的事件监听器。 有什么办法可以使其工作吗? 提前致谢!

Pavel asked 2019-10-08T14:55:41Z
9个解决方案
124 votes

AngularJS与Turbolinks

Turbolink和AnguluarJS都可以用来使Web应用程序更快地响应,在某种意义上,响应用户交互,网页上会发生某些事情,而无需重新加载和重新呈现整个页面。

它们在以下方面有所不同:

  • AngularJS帮助您构建一个丰富的客户端应用程序,在其中编写许多在客户端计算机上运行的JavaScript代码。 此代码使网站与用户互动。 它使用JSON API与服务器端后端进行通信,即与Rails应用程序进行通信。

  • 另一方面,Turbolinks有助于使网站具有交互性,而无需您编写JavaScript。 它使您能够坚持在服务器端运行的Ruby / Rails代码,并且仍然“神奇地”使用AJAX替换并因此仅重新渲染页面中已更改的部分。

Turbolinks可以让您无需使用任何手动操作即可完成此功能强大的AJAX机制,而仅对Ruby / Rails进行编码,而随着应用程序的增长,可能会出现一个阶段,您希望集成一个JavaScript框架(例如AngularJS)。

尤其是在这个中间阶段,您希望一次将AngularJS一次集成到您的应用程序中,一个组件,将Angular JS和Turbolinks一起运行是非常有意义的。

如何同时使用AngularJS和Turbolinks

使用回调手动引导Angular

在Angular代码中,有一行定义了您的应用程序模块,如下所示:

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

该代码在页面加载时运行。 但是,由于Turbolinks只是替换了页面的一部分并阻止了整个页面的加载,因此您必须确保正确地初始化了angular应用程序(“自举”),即使在Turbolinks进行了部分重新加载之后也是如此。 因此,将以下模块声明替换为以下代码:

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

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

不要自动引导

您通常会在教程中看到如何通过在HTML代码中使用ng-app属性来自动引导Angular应用。

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

但是,将此机制与上面显示的手动引导程序一起使用将导致应用程序两次引导,因此将导致应用程序停止运行。

因此,只需删除此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]
fiedl answered 2019-10-08T14:58:17Z
9 votes

Turbolinks试图优化页面的呈现,并与AngularJS的常规引导冲突。

如果您在应用程序的某些位置使用Turbolinks,并且某些部件使用Angular。 我提出了这个优雅的解决方案:

每个指向angularapp页面的链接(在其中使用ng-app =“ appname”)都应具有以下属性:

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

第二个-在Stackoverflow上提到的是通过处理page:load事件来显式地重新加载/引导每个ng-app。 我会打扰您,更不用说您可能正在加载页面上没有的内容,从而浪费资源。

我亲自使用了上述解决方案。

希望能帮助到你

jeveloper answered 2019-10-08T14:59:24Z
4 votes

发生错误时

未捕获的错误:[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']),但这会引起未编译内容的泛滥。

Artur Trzop answered 2019-10-08T15:00:18Z
1 votes

在客户端MVC框架中,Turbolinks不太有意义。 Turbolinks用于从服务器响应中剥离除正文以外的所有内容。 使用客户端MVC,您应该只将JSON传递给客户端,而不是HTML。

无论如何,turbolinks都会创建自己的回调。

page:load
page:fetch
page:restore
page:change
cpuguy83 answered 2019-10-08T15:01:01Z
1 votes

jquery.turbolinks插件可以通过ng-app指令触发模块的自举。 如果您尝试手动引导模块,则jquery.turbolinks可能导致ng:btstrpd错误。 我发现的一个警告是jquery.turbolinks依赖于page:load事件,该事件可以在任何新的特定于页面的<script>标签完成运行之前触发。 如果您在application.js之外包含模块定义,则可能导致$injector:nomod错误。 如果您确实希望将模块定义在仅包含在某些页面中的单独的javascript文件中,则可以通过data-no-turbolink禁用指向这些特定页面的任何链接上的涡轮链接。

Gabe Martin-Dempesy answered 2019-10-08T15:01:28Z
1 votes

将以下事件处理程序添加到您的应用程序。

咖啡脚本:

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加载每个页面后启动角度应用程序。

归功于[https://gist.github.com/ayamomiji/4736614]

Robin Daugherty answered 2019-10-08T15:02:31Z
0 votes

根据我所看到的评论,以Angular与Turbolink冲突的方式(例如允许Angular处理某些路由的方式)一起使用两者的唯一有效方案是,如果我有一个现有应用程序, 我试图移植到Angular。

就我个人而言,如果我要从头开始,我认为最好的解决方案是决定应该处理什么并坚持下去。 如果是Angular,那么摆脱Turbolinks->如果您的内容接近单页应用程序,对您没有多大帮助。 如果允许Rails处理路由,则只需使用Angular来组织客户端行为,这些行为在提供模板时服务器无法处理。

我在这里想念一个场景吗? 即使在大型应用程序中,尝试在不同框架之间划分路由职责似乎对我来说也不是一件好事。除了刷新页面或导航到新路线之外,是否还有其他一些Turbolink会干扰Angular的情况?

josiah answered 2019-10-08T15:03:19Z
0 votes

一起使用Turbolinks和AngularJS

向@fiedl +1以获得很好的答案。 但是我的首选是与page:load一起使用ng-app,因为它提供了一些灵活性:DOM可以从turbolinks之外的其他来源接收page:load事件,因此您可能不希望发生相同的回调。

注意ng-app,然后page:load应该将您的回调行为限制为仅turbolinks引发的事件。

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();

(这将允许/要求您像使用AngularJS时一样,将您的2560359438616101101888声明保留在html中。)

JellicleCat answered 2019-10-08T15:04:13Z
0 votes

Turbolinks自动获取页面,交换其ng-app,并合并其<html>,所有这些都不会导致加载整个页面的成本。

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

因此,我们可以在<body>元素上执行此操作,而不是在<html>元素上附加指令ng-app

<html>
  <body ng-app=“yourApplicationModuleName">
  </body>
</html>
Repolês answered 2019-10-08T15:04:59Z
translate from https://stackoverflow.com:/questions/14797935/using-angularjs-with-turbolinks