Using angles with turbo science

I am trying to use the Angularjs framework in my application with turbolinks. After changing the page, new eventlisteners are not initialized. Is this some way to make it work? Thanks in advance!

+59
angularjs ruby-on-rails turbolinks
Feb 10 '13 at
source share
9 answers

AngularJS vs Turbolinks

Turbolinks , as well as AnguluarJS, can be used to make a web application respond faster in the sense that in response to user interaction, something happens on the web page without reloading and reloading the entire page.

They differ in the following respects:

  • AngularJS helps you create a rich client application where you write a lot of JavaScript code that runs on the client machine. This code makes the site interactive for the user. It interacts with the server on the server side, that is, with the Rails application using the JSON API.

  • Turbolinks , on the other hand, helps make a site interactive without the need for JavaScript code. This allows you to adhere to server-side Ruby / Rails code and still “magically” use AJAX to replace and, therefore, redefine only those parts of the page that have changed.

Where Turbolinks is strong in that you can use this powerful AJAX engine without any manual actions and just Ruby / Rails code, a step may arise as your application grows where you would like to integrate a JavaScript framework such as AngularJS ,

Especially at this intermediate stage, when you would like to consistently integrate AngularJS into your application, one component at a time, it might make sense to run Angular JS and Turbolinks together.

How to use AngularJS and Turbolinks together

Use callback for Angular manual bootstrap

In Angular code, you have a line defining your application module, something like this:

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

This code runs when the page loads. But since Turbolinks simply replaces part of the page and prevents the entire page from loading, you need to make sure that the Angular application is properly initialized (“loaded”) even after such partial reboots made by Turbolinks. Thus, replace the above module declaration with the following code:

 # app/assets/javascripts/angular-app.js.coffee # with turbolinks @app = angular.module 'MyApplication', ['ngResource'] $(document).on 'turbolinks:load', -> angular.bootstrap document.body, ['MyApplication'] 

Do not download automatically

In tutorials, you often see how to automatically download an Angular application using the ng-app attribute in your HTML code.

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

But using this mechanism together with the manual bootstrap shown above will cause the application to load twice and therefore block the application.

So just remove this ng-app attribute:

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

additional literature

+124
Mar 18 '13 at 23:34
source share

Turbolinks is trying to optimize page rendering and will conflict with regular AngularJS bootstraping.

If you use Turbolinks in some places of your application, some parts use Angular. I offer this elegant solution:

Each link to the angularapp page (where you use ng-app = "appname") should have this attribute:

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

The second mention of Stackoverflow explicitly reloads / loads each ng application, processing the page: load event. I would be obsessive, not to mention the fact that you are potentially loading something that is not on the page, so it is wasting resources.

I personally used the above solution.

Hope this helps

+9
Aug 11 '14 at 18:38
source share

In case of error

Unprepared error: [ng: btstrpd] Application already loaded with this 'document' element

after upgrading to angular 1.2.x you can use below to fix the problem.

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

In a previous post, @nates suggested changing angular.bootstrap(document, ['YourApplication']) to angular.bootstrap("body", ['YourApplication']) , but this causes unrelated content to appear.

+4
Jan 12 '14 at 4:00 p.m.
source share

Turbolinks is not well understood with the MVC client environment. Turbolinks is used to cut everything except the body from the server response. With client-side MVC, you should simply pass JSON to the client, not HTML.

In any case, turbolinks creates its own callbacks.

 page:load page:fetch page:restore page:change 
+1
Feb 10 '13 at
source share

Add the following event handler to the application.

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

This will launch the angular application after each page loaded by Turbolinks.

Credit https://gist.github.com/ayamomiji/4736614

+1
Oct 03 '13 at 0:06 on
source share

The jquery.turbolinks plugin can initiate module loading using the ng-app directives. If you try to manually load modules, jquery.turbolinks can lead to ng: btstrpd errors. One caveat I discovered is that jquery.turbolinks relies on the page:load event, which can be fired before all the <script> tags for each page have finished executing. This can lead to $injector:nomod if you include module definitions outside application.js. If you really want your modules to be defined in separate javascript files that are included only on certain pages, you can simply disable turbolinks on any links to those specific pages via data-no-turbolink .

+1
Jan 08 '14 at 10:32
source share

Based on the comments I saw, the only valid script to use both together in such a way that Angular will conflict with Turbolinks (for example, when I allow Angular to handle some routing) is if I have an existing application that I'm trying to connect to Angular.

Personally, if I did this from scratch, I think the best solution would be to decide what should handle the routing and stick to it. If Angular has anything to do with Turbolinks →, it will not help you if you have something close to a single-page application. If you enable Rails to handle routing, just use Angular to organize client-side behavior that the server cannot handle when servicing templates.

Did I miss the script here? It doesn’t seem elegant to me to try to divide routing responsibilities between different frameworks even in a large application ... Is there any other scenario when Turbolinks will interfere with Angular, besides refreshing the page or moving to a new route?

0
Feb 22 '15 at 22:19
source share

Using Turbolinks and AngularJS Together

+1 for @fiedl for a great answer. But I prefer to use page:change conjunction with page:load , because it gives some flexibility: the DOM can receive the page:load event from sources other than turbolinks, so you may not want to have the same callback.

Watching page:change , then page:load should limit your callback behavior solely to events triggered by the turbine.

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

(This will allow / requires that you save your ng-app declaration in your html, as usual when working with AngularJS.)

0
Jun 27 '15 at 16:35
source share

Turbolinks automatically extracts the page, swaps it into <body> and merges it into <head> , all without the cost of a full page load.

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

So, instead of the append ng-app directive in the <html> element, we can just do it in the <body> element.

 <html> <body ng-app="yourApplicationModuleName"> </body> </html> 
0
Apr 28 '16 at 22:25
source share



All Articles