web-dev-qa-db-fra.com

Alternative (document) .ready pour AngularJS

J'utilise un modèle appelé Gentelella et j'essaye d'y implémenter AngularJS. Cependant, je rencontre un problème avec un certain fichier Javascript. À la fin de ce fichier, une fonction $(document).ready est appelée, elle initialise le code Javascript qui apporte certaines modifications au code HTML. Le problème est que la fonction $(document).ready est appelée trop tôt, avant que le code HTML ne soit complètement chargé. 

Ce problème est probablement dû au fait que j'utilise ngRoute et que cela injecte le fichier HTML de modèle dans la vue ng du fichier index.html. Dans ce cas, le DOM annonce probablement déjà qu'un document est prêt avant qu'AngularJS n'ait injecté le modèle (= HTML).

Donc, fondamentalement, je dois juste trouver un moyen d’appeler du code dans un fichier Javascript une fois que AngularJS a injecté le modèle.

J'ai joint un code pour mieux comprendre le problème:

Extrait du custom.min.js

$(document).ready(function () {
  init_sparklines(), init_flot_chart(), init_sidebar(), init_wysiwyg(), init_InputMask(), ...
});

Extrait du fichier main.js:

.config(function($routeProvider, $httpProvider) {

  $routeProvider.when('/', {
    templateUrl : 'dash.html',
    controller : 'dash',
    controllerAs: 'controller'
  }).when('/login', {
    templateUrl : 'login.html',
    controller : 'navigation',
    controllerAs: 'controller'
  }).when('/plain_page', {
    templateUrl : 'plain_page.html',
    controller : 'dash',
    controllerAs: 'controller'
  }).otherwise('/');

  $httpProvider.defaults.headers.common["X-Requested-With"] = 'XMLHttpRequest';

})

Merci d'avance!

3
Jérémy

De nombreux plugins jQuery dépendent d'un flux de travail de 1. dessinez le DOM. 2. Exécutez une fonction init() pour configurer le code par rapport à ces éléments DOM. 

Ce flux de travail est médiocre dans Angular, car le DOM n'est pas statique: Angular configure et détruit les nœuds DOM sur son propre cycle de vie, ce qui peut écraser les liaisons d'événement ou les modifications DOM effectuées en dehors de Angular. Le document prêt n'est pas particulièrement utile lorsque vous utilisez Angular, car il indique simplement que Angular est prêt à être lancé. 

Pour utiliser Angular efficacement, vous devez prendre l’habitude d’initier du code uniquement lorsque cela est réellement nécessaire. Ainsi, au lieu d'un gros compartiment de init_foo(); init_bar(); sur document.ready, vous devriez avoir une directive Foo avec son propre code init, et une directive Bar avec son propre code init, et ainsi de suite. Chacune de ces directives ne doit modifier que le DOM créé par cette directive spécifique. C'est le seul moyen sûr de s'assurer que les éléments DOM que vous devez modifier existent réellement et que vous ne créez pas de conflits ou d'interdépendances inattendues entre les directives.

Prenons un exemple. Je suppose que votre init_flot_chart() parcourt le DOM à la recherche d’un élément particulier à l’intérieur duquel il dessine un diagramme à puces. Au lieu de cette approche descendante, créez une directive:

angular.module('yourApp')
  .directive('flotWrapper', function () {
    return {
      template: "<div></div>",
      scope: {
        data: '@'
      },
      link: function(scope, elem, attrs) {
        var options = {}; // or could pass this in as an attribute if desired
        $.plot(elem, scope.data, options); // <-- this calls flot on the directive's element; no DOM crawling necessary
      }
    };
});

que vous utilisez comme ceci:

<flot-wrapper data="{{theChartData}}"></flot-wrapper>

... où theChartData est un objet contenant les données à dessiner dans le graphique. (Vous pouvez ajouter d'autres attributs à transmettre, quels que soient les autres paramètres de votre choix, tels que les options d'invocations, un titre, etc.) 

Lorsque Angular dessine cette directive flotWrapper, il crée d'abord le ou les éléments DOM dans le modèle de directive, puis exécute ce qui se trouve dans sa fonction link sur l'élément racine du modèle. (La bibliothèque Flot elle-même peut être incluse via une ancienne balise <script> afin que sa fonction plot soit disponible lorsque la directive en a besoin.)

(Notez que cela ne se mettrait pas à jour automatiquement si le contenu de theChartData change; un exemple plus élaboré, qui surveille également les modifications et réagit de manière appropriée, peut être vu ici .)

4
Daniel Beck

Comme vous utilisez ngRoute, votre contrôleur s'exécutera lorsque la page sera chargée. Vous pouvez appeler une méthode init() dès que le contrôleur commence à faire ce que vous voulez.

function MyCtrl($scope) {
    function init() {
        console.log('controller started!');
    }
    init();
}

A noter que c’est une pratique recommandée dans Le guide de John Papa Angular .


Une autre possibilité consiste à utiliser la directive ng-init , par exemple:

<div ng-controller="MyCtrl" ng-init="myFunction()">...</div>
1
Mistalis

Il existe un hook de cycle de vie nommé $postLink() dans la version récente de angular.js, appelé après que les éléments de ce contrôleur et ses enfants aient été liés. Semblable à la fonction post-link, ce crochet peut être utilisé pour configurer des gestionnaires d’événements DOM et effectuer une manipulation directe du DOM.Check the guide

0
B.Ma