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 !
Réponses
Trop de publicités?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
- Amorçage d'AngularJS : http://docs.angularjs.org/guide/bootstrap
- Railscasts sur Turbolinks (explique les callbacks) : http://railscasts.com/episodes/390-turbolinks
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
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é.
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
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.