J'ai une fonction dans mon contrôleur angulaire, je voudrais que cette fonction soit exécutée sur document prêt mais j'ai remarqué que angular l'exécute lorsque 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 m'y prendre?
Nous pouvons utiliser la méthode angular.element(document).ready()
pour attacher des rappels lorsque le document est prêt. Nous pouvons simplement attacher le rappel dans le contrôleur de la manière suivante:
angular.module('MyApp', [])
.controller('MyCtrl', [function() {
angular.element(document).ready(function () {
document.getElementById('msg').innerHTML = 'Hello';
});
}]);
Voir cet article Comment exécuter la fonction de contrôleur angulaire lors du chargement de la 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 ne devez pas attendre que le document soit prêt.
Angular s’initialise automatiquement sur un événement
DOMContentLoaded
ou lorsque le script angular.js est évalué si, à ce moment, document.readyState est réglé sur 'complet'. À ce stade, Angular recherche l'application ng directive qui désigne la racine de votre application.
https://docs.angularjs.org/guide/bootstrap
Cela signifie que le code du contrôleur sera exécuté une fois que le DOM est prêt.
Donc, c'est juste $scope.init()
.
Angular a plusieurs points horaires pour commencer à exécuter des fonctions. Si vous cherchez quelque chose comme jQuery
$(document).ready();
Vous pouvez trouver cet analogue en angulaire très utile:
$scope.$watch('$viewContentLoaded', function(){
//do something
});
Celui-ci est utile lorsque vous souhaitez manipuler les éléments DOM. Il ne commencera à s'exécuter qu'une fois tous les éléments chargés.
UPD: Ce qui est dit ci-dessus fonctionne lorsque vous souhaitez modifier les propriétés CSS. Cependant, parfois, cela ne fonctionne pas lorsque vous souhaitez mesurer les propriétés de l'élément, telles que la largeur, la hauteur, etc. Dans ce cas, vous pouvez essayer ceci:
$scope.$watch('$viewContentLoaded',
function() {
$timeout(function() {
//do something
},0);
});
Dans une situation similaire, j'avais besoin d'exécuter une fonction de contrôleur après le chargement de la vue et également après le chargement, l'initialisation d'un composant tiers particulier dans la vue, et pour avoir placé une référence à lui-même sur $ scope. Ce qui a fini par travailler pour moi a été de mettre en place une surveillance sur cette propriété de portée et d’activer ma fonction uniquement après son initialisation.
// $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é plusieurs fois avec des valeurs indéfinies. Ensuite, lorsque la grille est créée et possède la propriété attendue, la fonction d'initialisation peut être appelée en toute sécurité. La première fois que l'observateur est appelé avec une newValue non indéfinie, oldValue sera toujours indéfinie.
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és. Dans une page d’exemple comportant 4 composants, tous générant du HTML à partir d’un modèle, l’ordre des événements a été modifié.
$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, $ document.ready () est inutile dans la plupart des cas car le DOM en construction angulaire est loin d’être prêt.
Mais plus intéressant encore, même après le lancement de $ viewContentLoaded, l’élément d’intérêt est toujours introuvable.
Ce n'est qu'après que $ timeout a été exécuté. Notez que bien que $ timeout ait la valeur 0, près de 200 millisecondes se sont écoulées avant son exécution, ce qui indique que ce thread a été bloqué pendant un bon bout de temps, probablement lorsque le modèle DOM a ajouté des modèles angulaires à un thread principal. Le temps total écoulé entre le premier $ document.ready () et la dernière exécution de $ timeout était de près de 500 millisecondes.
Dans un cas extraordinaire où la valeur d'un composant était définie, puis la valeur text () changée plus tard dans $ timeout, la valeur de $ timeout devait être augmentée jusqu'à ce que cela fonctionne (même si l'élément pouvait être trouvé pendant le $ timeout ). Un élément asynchrone dans le composant tiers a fait qu'une valeur a priorité sur le texte jusqu'à ce que le temps soit écoulé. Une autre possibilité est $ scope. $ EvalAsync, mais n’a pas été essayée.
Je suis toujours à la recherche de cet événement qui me dit que le DOM est complètement installé et peut être manipulé pour que tous les cas fonctionnent. Jusqu'à présent, une valeur de délai d'attente arbitraire est nécessaire, ce qui signifie qu'il s'agit, au mieux, d'un problème qui peut ne pas fonctionner avec un navigateur lent. Je n'ai pas essayé les options JQuery telles que liveQuery et publish/subscribe qui peuvent fonctionner, mais ne sont certainement pas angulaires.
Voici ma tentative à l'intérieur d'un contrôleur externe en utilisant Coffeescript. Ça marche plutôt bien. Veuillez noter que settings.screen.xs | sm | md | lg sont des valeurs statiques définies dans un fichier non uglifié que j'inclus avec l'application. Les valeurs sont basées sur les points d'arrêt officiels Bootstrap 3 pour les tailles de requête de média éponyme:
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()
$scope.$on('$ViewData', function(event) {
//Your code.
});
Si vous obtenez quelque chose comme getElementById call returns null
, c'est probablement parce que la fonction est en cours d'exécution, mais l'ID n'a pas eu le temps de charger dans le DOM.
Essayez d’utiliser la réponse de Will (vers le haut) avec un retard. Exemple:
angular.module('MyApp', [])
.controller('MyCtrl', [function() {
$scope.sleep = (time) => {
return new Promise((resolve) => setTimeout(resolve, time));
};
angular.element(document).ready(function () {
$scope.sleep(500).then(() => {
//code to run here after the delay
});
});
}]);
Pourquoi ne pas essayer avec quels docs angulaires mentionnent https://docs.angularjs.org/api/ng/function/angular.element .
angular.element (rappel)
J'ai utilisé cela dans ma fonction $ onInit () {...}.
var self = this;
angular.element(function () {
var target = document.getElementsByClassName('unitSortingModule');
target[0].addEventListener("touchstart", self.touchHandler, false);
...
});
Cela a fonctionné pour moi.