59 votes

Utilisation d'angularjs avec turbolinks

J'essaie d'utiliser le framework Angularjs dans mon application avec des turbolinks. Après un changement de page, il n'initialise pas les nouveaux eventlisteners. Y a-t-il un moyen de le faire fonctionner ? Merci d'avance !

125voto

fiedl Points 1367

AngularJS vs. Turbolinks

Turbolinks ainsi que AnguluarJS peuvent toutes deux être utilisées pour accélérer la réponse d'une application web, en ce sens qu'en réponse à une interaction de l'utilisateur, quelque chose se passe sur la page web sans qu'il soit nécessaire de recharger et de rendre à nouveau la page entière.

Ils diffèrent sur les points suivants :

  • AngularJS vous aide à construire un application riche côté client où vous écrivez beaucoup de code JavaScript qui s'exécute sur la machine du client. Ce code rend le site interactif pour l'utilisateur. Il communique avec le backend côté serveur, c'est-à-dire avec l'application Rails, en utilisant une API JSON.

  • Turbolinks En revanche, il permet de rendre le site interactif sans avoir à coder du JavaScript. Il vous permet de s'en tenir au code Ruby/Rails s'exécutent côté serveur et continuent, "comme par magie", à utiliser AJAX pour remplacer, et donc rendre à nouveau, uniquement les parties de la page qui ont changé.

Là où Turbolinks a la force de vous permettre d'utiliser ce puissant mécanisme AJAX sans rien faire à la main et en codant simplement Ruby/Rails, il se peut qu'à un moment donné, lorsque votre application se développe, vous souhaitiez intégrer un framework JavaScript tel qu'AngularJS.

En particulier dans cette phase intermédiaire, où vous souhaitez intégrer successivement AngularJS dans votre application, un composant à la fois, il peut être parfaitement logique d'exécuter Angular JS et Turbolinks ensemble.

Comment utiliser AngularJS et Turbolinks ensemble ?

Utiliser un callback pour amorcer manuellement Angular

Dans votre code Angular, vous avez une ligne définissant votre module d'application, quelque chose comme ceci :

# app/assets/javascripts/angular-app.js.coffee
# without turbolinks
@app = angular.module("YourApplication", ["ngResource"])

Ce code est exécuté lorsque la page est chargée. Mais comme Turbolinks ne fait que remplacer une partie de la page et empêche le chargement complet de la page, vous devez vous assurer que l'application angulaire est correctement initialisée ("bootstrapped"), même après ces rechargements partiels effectués par Turbolinks. Ainsi, remplacez la déclaration du module ci-dessus par le code suivant :

# app/assets/javascripts/angular-app.js.coffee
# with turbolinks
@app = angular.module("YourApplication", ["ngResource"])

$(document).on('ready page:load', ->
  angular.bootstrap(document, ['YourApplication'])
)

Ne pas faire de bootstrap automatique

On voit souvent dans les tutoriels comment amorcer automatiquement une application Angular en utilisant la fonction ng-app dans votre code HTML.

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

Mais l'utilisation de ce mécanisme en même temps que l'amorçage manuel présenté ci-dessus entraînerait un double amorçage de l'application et, par conséquent, freinerait l'application.

Ainsi, il suffit de supprimer ce ng-app attribut :

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

Autres lectures

9voto

jeveloper Points 224

Les Turbolinks tentent d'optimiser le rendu des pages et entreraient en conflit avec l'amorçage normal d'AngularJS.

Si vous utilisez Turbolinks à certains endroits de votre application et que certaines parties utilisent Angular. Je propose cette solution élégante :

Chaque lien vers une page angularapp (où vous utilisez ng-app="appname") doit avoir cet attribut :

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

La seconde - mentionnée sur Stackoverflow - consiste à recharger/bootstrapper explicitement chaque ng-app en traitant l'événement page:load. Je pense que c'est intrusif, sans parler du fait que vous chargez potentiellement quelque chose qui n'est pas sur une page, d'où un gaspillage de ressources.

J'ai personnellement utilisé la solution ci-dessus.

J'espère que cela vous aidera

4voto

ArturT Points 113

En cas de bug

Erreur involontaire : [ng:btstrpd] L'application est déjà amorcée avec cet élément. Élément 'document'.

après la mise à jour vers angular 1.2.x, vous pouvez utiliser les outils ci-dessous pour résoudre le problème.

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

Dans le post précédent, @nates a proposé de changer angular.bootstrap(document, ['YourApplication']) a angular.bootstrap("body", ['YourApplication']) mais cela provoque un flash de contenu non compilé.

1voto

cpuguy83 Points 1811

Turbolinks n'a pas vraiment de sens avec un cadre MVC côté client. Turbolinks est utilisé pour retirer tout sauf le corps de la réponse du serveur. Avec un MVC côté client, vous devriez juste passer du JSON au client, pas du HTML.

Dans tous les cas, turbolinks crée ses propres callbacks.

page:load
page:fetch
page:restore
page:change

1voto

Robin Daugherty Points 1111

Ajoutez le gestionnaire d'événements suivant à votre application. (C'est du Coffeescript.)

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

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

Ainsi, l'application angulaire sera lancée après chaque page chargée par Turbolinks.

Crédit à https://gist.github.com/ayamomiji/4736614

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X