Comment exécuter la fonction dans le contrôleur angulaire sur le document prêt?
j'ai une fonction à l'intérieur de mon contrôleur angulaire, je voudrais que cette fonction soit exécutée sur document ready mais j'ai remarqué qu'angular l'exécute au fur et à mesure que le dom est créé.
function myController($scope)
{
$scope.init = function()
{
// I'd like to run this on document ready
}
$scope.init(); // doesn't work, loads my init before the page has completely loaded
}
Quelqu'un sait comment je peux faire ça?
9 réponses
nous pouvons utiliser la méthode angular.element(document).ready()
pour joindre les callbacks lorsque le document est prêt. Nous pouvons simplement fixer le rappel dans le contrôleur comme ceci:
angular.module('MyApp', [])
.controller('MyCtrl', [function() {
angular.element(document).ready(function () {
document.getElementById('msg').innerHTML = 'Hello';
});
}]);
voir ce post comment exécuter la fonction de contrôleur angulaire sur la charge de page?
Pour une recherche rapide:
// register controller in html
<div data-ng-controller="myCtrl" data-ng-init="init()"></div>
// in controller
$scope.init = function () {
// check if there is query in url
// and fire search in case its value is not empty
};
de cette façon, vous n'avez pas à attendre jusqu'à ce que le document soit prêt.
angle initialise automatiquement lors de l'événement
DOMContentLoaded
ou lorsque l'angulaire.js script est évalué si à l'époque document.readyState est "complète". À ce point angulaire cherche le ng-app directive qui désigne votre application root.
https://docs.angularjs.org/guide/bootstrap
cela signifie que le code du contrôleur s'exécute après que le DOM est prêt.
donc c'est juste $scope.init()
.
Angular a plusieurs points temporels pour commencer à exécuter des fonctions. Si vous cherchez quelque chose comme jQuery
$(document).ready();
vous pouvez trouver cet analogue en angle très utile:
$scope.$watch('$viewContentLoaded', function(){
//do something
});
celui-ci est utile quand vous voulez manipuler les éléments DOM. Il ne commencera à s'exécuter qu'une fois tous les éléments te chargés.
UPD: ce qui est dit ci-dessus fonctionne lorsque vous voulez changer les propriétés css. Cependant, parfois, cela ne fonctionne pas quand vous voulez mesurer les propriétés de l'élément, comme la largeur, la hauteur, etc. Dans ce cas, vous pouvez essayer ceci:
$scope.$watch('$viewContentLoaded',
function() {
$timeout(function() {
//do something
},0);
});
j'ai eu une situation similaire où j'ai dû exécuter une fonction de contrôleur après que la vue ait été chargée et aussi après qu'un composant tiers particulier dans la vue ait été chargé, initialisé, et ait placé une référence à lui-même sur $scope. Ce qui a fini par marcher pour moi était de configurer une montre sur cette propriété scope et de virer ma fonction seulement après qu'elle ait été initialisée.
// $scope.myGrid property will be created by the grid itself
// The grid will have a loadedRows property once initialized
$scope.$watch('myGrid', function(newValue, oldValue) {
if (newValue && newValue.loadedRows && !oldValue) {
initializeAllTheGridThings();
}
});
l'observateur est appelé quelques fois avec des valeurs non définies. Puis, quand la la grille est créé et a la propriété attendue, la fonction d'initialisation peut être appelé en toute sécurité. La première fois que l'observateur est appelé avec une nouvelle valeur non-définie, oldValue sera encore indéterminée.
voici ma tentative à l'intérieur d'un contrôleur externe en utilisant coffeescript. Il fonctionne plutôt bien. Veuillez noter que les paramètres.écran.xs|sm|md / lg sont des valeurs statiques définies dans un fichier non-uglified que j'inclus avec l'application. Les valeurs sont par le Bootstrap 3 points de rupture officiels pour les tailles de requête de médias éponymes:
xs = settings.screen.xs // 480
sm = settings.screen.sm // 768
md = settings.screen.md // 992
lg = settings.screen.lg // 1200
doMediaQuery = () ->
w = angular.element($window).width()
$scope.xs = w < sm
$scope.sm = w >= sm and w < md
$scope.md = w >= md and w < lg
$scope.lg = w >= lg
$scope.media = if $scope.xs
"xs"
else if $scope.sm
"sm"
else if $scope.md
"md"
else
"lg"
$document.ready () -> doMediaQuery()
angular.element($window).bind 'resize', () -> doMediaQuery()
La réponse
$scope.$watch('$viewContentLoaded',
function() {
$timeout(function() {
//do something
},0);
});
est le seul qui fonctionne dans la plupart des scénarios que j'ai testé. Dans une page d'exemple avec 4 composants tous qui construisent HTML à partir d'un modèle, l'ordre des événements était
$document ready
$onInit
$postLink
(and these 3 were repeated 3 more times in the same order for the other 3 components)
$viewContentLoaded (repeated 3 more times)
$timeout execution (repeated 3 more times)
donc un document à$.ready() est inutile dans la plupart des cas puisque le DOM construit en angle peut être loin d'être prêt.
mais plus intéressant, même après le lancement de $viewcontentload, le aucun élément intéressant n'a pu être trouvé.
N'a été trouvé qu'après l'exécution de $timeout. Notez que même si $timeout était une valeur de 0, près de 200 millisecondes se sont écoulées avant qu'il ne soit exécuté, ce qui indique que ce thread a été bloqué pendant un certain temps, probablement alors que le DOM avait des gabarits angulaires ajoutés sur un thread principal. Le temps total à partir du premier document$.prêt() à la dernière $timeout exécution a été de près de 500 millisecondes.
dans un cas extraordinaire où la valeur d'un composant a été définie et que la valeur textuelle() a été changée plus tard dans $timeout, la valeur $timeout a dû être augmentée jusqu'à ce qu'elle fonctionne (même si l'élément pouvait être trouvé pendant $timeout). Quelque chose d'async dans le composant tiers a fait qu'une valeur a eu la priorité sur le texte jusqu'à ce que suffisamment de temps se soit écoulé. Une autre possibilité est $scope.$evalAsync, mais n'a pas été essayé.
je suis toujours à la recherche de cet événement qui dit moi le DOM est complètement installé et peut être manipulé pour que tous les cas fonctionnent. Jusqu'à présent arbitraire valeur de délai d'expiration est nécessaire, ce qui signifie, au mieux, c'est une bidouille qui peut ne pas fonctionner sur un navigateur lent. Je n'ai pas essayé les options JQuery comme liveQuery et publish/subscribe qui peuvent fonctionner, mais ne sont certainement pas purement angulaires.
pourquoi ne pas essayer avec ce que les docs angulaires mentionnent https://docs.angularjs.org/api/ng/function/angular.element .
angulaire.élément(rappel)
j'ai utilisé ce à l'intérieur de mon $onInit(){...} fonction.
var self = this;
angular.element(function () {
var target = document.getElementsByClassName('unitSortingModule');
target[0].addEventListener("touchstart", self.touchHandler, false);
...
});
ça a marché pour moi.
$scope.$on('$ViewData', function(event) {
//Your code.
});