Ruby on rails 将angularjs与TurboLink一起使用

Ruby on rails 将angularjs与TurboLink一起使用,ruby-on-rails,angularjs,turbolinks,Ruby On Rails,Angularjs,Turbolinks,我正在尝试在我的应用程序中使用Angularjs框架和TurboLink。页面更改后,它不会初始化新的eventlisteners。有什么办法可以让它工作吗?提前谢谢 Turbolinks对于客户端MVC框架没有太大意义。TurboLink用于从服务器响应中除去除正文以外的所有内容。使用客户端MVC,您应该只向客户端传递JSON,而不是HTML 在任何情况下,TurboLink都会创建自己的回调 page:load page:fetch page:restore page:change Ang

我正在尝试在我的应用程序中使用Angularjs框架和TurboLink。页面更改后,它不会初始化新的eventlisteners。有什么办法可以让它工作吗?提前谢谢

Turbolinks对于客户端MVC框架没有太大意义。TurboLink用于从服务器响应中除去除正文以外的所有内容。使用客户端MVC,您应该只向客户端传递JSON,而不是HTML

在任何情况下,TurboLink都会创建自己的回调

page:load
page:fetch
page:restore
page:change
AngularJS vs.Turbolinks TurbolinksAnguluarJS都可以用于使web应用程序响应更快,因为响应用户交互时,网页上会发生一些事情,而无需重新加载和重新提交整个页面

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

  • AngularJS帮助您构建一个富客户端应用程序,您可以在该应用程序中编写大量在客户端计算机上运行的JavaScript代码。此代码使站点与用户交互。它使用JSON API与服务器端后端通信,即与Rails应用程序通信

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

当Turbolinks强大到可以让您不用手工编写Ruby/Rails代码就可以使用这种强大的AJAX机制时,随着应用程序的增长,您可能会希望集成一个JavaScript框架,比如AngularJS

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

如何同时使用AngularJS和TurboLink 使用回调手动引导 在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">
  ...
进一步阅读
  • AngularJS引导:
  • TurboLink上的Railscasts(解释回调):
  • 演示应用程序:

将以下事件处理程序添加到应用程序中

咖啡脚本:

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);
这将导致在TurboLink加载每个页面后启动angular应用程序

归功于

该插件可以通过ng应用程序指令触发模块引导。如果您试图手动引导模块,jquery.turbolinks可能会导致ng:btstrpd错误。我发现的一个警告是jquery.turbolinks依赖于
page:load
事件,它可以在任何新的特定于页面的
标记完成运行之前触发。如果在application.js之外包含模块定义,这可能会导致
$injector:nomod
错误。如果您确实希望在单独的javascript文件中定义模块,并且这些文件只包含在特定页面上,那么您可以通过
data no turbolink

在指向这些特定页面的任何链接上定义模块,以防出现错误

未捕获错误:[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(文档,['YourApplication'])
更改为
angular.bootstrap(“正文,['YourApplication'])
,但这会导致未编译内容的闪烁。

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

如果您在应用程序的某些位置使用TurboLink,并且某些部分使用Angular。我建议这个优雅的解决方案:

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

<!-- app/views/layouts/my_layout.html.erb -->
<!-- with turbolinks -->
<html>
  ...
<a href="/myapp" data-no-turbolink>Say NO to Turbolinks</a>.
Stackoverflow中提到的第二个问题是通过处理page:load事件显式地重新加载/引导每个ng应用程序。我认为这是侵入性的,更不用说你可能会加载一些不在页面上的东西,从而浪费资源

我个人使用了上述解决方案


希望它能有所帮助

根据我看到的评论,如果Angular与TurboLink冲突(例如我允许Angular处理一些路由),那么将两者结合使用的唯一有效方案是,如果我有一个正在尝试移植到Angular的现有应用程序

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

我是不是错过了一个场景?在我看来,试图在不同的框架之间划分路由责任似乎并不优雅,即使在大型应用程序中也是如此。。。除了刷新页面或导航到新路线之外,Turbolinks还会干扰AngularJS吗?

同时使用Turbolinks和AngularJS +1到@fiedl获得一个很好的答案。但我更喜欢利用
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();
<html>
  <body ng-app=“yourApplicationModuleName">
  </body>
</html>