Comment exécuter la fonction de contrôleur AngularJS au chargement de la page?

360

Actuellement, j'ai une page Angular.js qui permet de rechercher et d'afficher les résultats. L'utilisateur clique sur un résultat de recherche, puis clique sur le bouton de retour. Je souhaite que les résultats de la recherche s'affichent à nouveau, mais je n'arrive pas à déterminer comment déclencher l'exécution de la recherche. Voici le détail:

  • Ma page Angular.js est une page de recherche, avec un champ de recherche et un bouton de recherche. L'utilisateur peut saisir manuellement une requête et appuyer sur un bouton. La requête ajax est déclenchée et les résultats sont affichés. Je mets à jour l'URL avec le terme de recherche. Tout fonctionne bien.
  • L'utilisateur clique sur un résultat de la recherche et est redirigé vers une autre page - cela fonctionne également très bien.
  • L'utilisateur clique sur le bouton Précédent et retourne à ma page de recherche angulaire, et l'URL correcte s'affiche, y compris le terme de recherche. Tout fonctionne bien.
  • J'ai lié la valeur du champ de recherche au terme de recherche dans l'URL, il contient donc le terme de recherche attendu. Tout fonctionne bien.

Comment puis-je exécuter à nouveau la fonction de recherche sans que l'utilisateur n'ait à appuyer sur le "bouton de recherche"? Si c'était jquery, j'exécuterais une fonction dans la fonction documentready. Je ne peux pas voir l'équivalent Angular.js.

Duke Dougal
la source
utilisez-vous $routepProvider? Utilisez-le pour vous connecter au service de votre application qui fournit des données pour les résultats de la recherche. Ne pensez pas en document.readytermes comme avec jQuery. Difficile d'aider beaucoup sans voir comment vous avez actuellement la recherche câblée
charlietfl

Réponses:

430

D'une part, comme @ Mark-Rajcok l'a dit, vous pouvez simplement vous en sortir avec une fonction intérieure privée:

// at the bottom of your controller
var init = function () {
   // check if there is query in url
   // and fire search in case its value is not empty
};
// and fire it after definition
init();

Vous pouvez également consulter la directive ng-init . La mise en œuvre ressemblera beaucoup à:

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

Mais attention à cela car la documentation angulaire implique (depuis la v1.2) de ne PAS l'utiliser ng-initpour cela. Cependant, cela dépend de l'architecture de votre application.

J'ai utilisé ng-initlorsque je voulais transmettre une valeur du back-end à l'application angulaire:

<div data-ng-controller="myCtrl" data-ng-init="init('%some_backend_value%')"></div>
Dmitry Evseev
la source
6
@Duke, ne pouvez-vous pas simplement mettre le contenu de la fonction init () au bas de votre contrôleur? C'est-à-dire, pourquoi avez-vous besoin d'utiliser ng-init et d'avoir une fonction init ()? Lorsque l'utilisateur appuie sur le bouton de retour, je suppose que vous changez de vue, donc un nouveau myCtrlcontrôleur est créé et s'exécute.
Mark Rajcok
24
Bien que cette solution fonctionne, j'ai rétrogradé car la documentation ng-init déconseille cela. Plus précisément, «La seule utilisation appropriée de ngInit pour aliaser les propriétés spéciales de ngRepeat, comme indiqué dans la démonstration ci-dessous. En plus de ce cas, vous devez utiliser des contrôleurs plutôt que ngInit pour initialiser des valeurs sur une étendue.
Jason Capriotti
1
Le contrôleur est instancié une fois que le HTML est à sa place.
Dmitry Evseev
3
Que se passe-t-il si le contrôleur est réutilisé dans d'autres pages mais que vous souhaitez simplement le déclencher sur une page spécifique?
Roberto Linares
3
@RobertoLinares Je trouve personnellement que les directives sont un meilleur endroit pour les fonctionnalités réutilisables. Vous pouvez avoir une directive avec un paramètre INIT: <div smth on-init="doWhatever()">. Bien sûr, cela dépend d'un certain cas d'utilisation.
Dmitry Evseev
135

Essaye ça?

$scope.$on('$viewContentLoaded', function() {
    //call it here
});
principe holographique
la source
5
Merci pour la réponse mais la réponse de Dmitry correspondait exactement à ce que je cherchais. Des recherches supplémentaires semblaient recommander contre $ viewContentLoaded
Duke Dougal
7
Les cas d'utilisation sont juste différents. J'utilise également la méthode de Mark tout le temps.
principe holographique
Pour mon cas d'utilisation, c'était une solution parfaite. Nous devions sélectionner automatiquement le texte pour encourager l'utilisateur à le copier. La page a pu être rechargée / revisitée plusieurs fois, donc $ viewContentLoaded était une correspondance exacte. Merci!
Olga Gnatenko
Est-il possible que cela soit exécuté plusieurs fois? Je reçois un comportement qui semble imiter cela ...
MadPhysicist
1
Celui-ci ne fonctionnait pas pour moi mais $ scope. $ Watch fonctionnait. Quelle est la principale différence?
Burak Tokak
59

Je ne pourrais jamais me mettre $viewContentLoadedau travail et ng-initne devrait vraiment être utilisé que dans un ng-repeat(selon la documentation), et aussi appeler une fonction directement dans un contrôleur peut provoquer des erreurs si le code repose sur un élément qui n'a pas encore été défini .

C'est ce que je fais et ça fonctionne pour moi:

$scope.$on('$routeChangeSuccess', function () {
  // do something
});

Sauf si vous utilisez ui-router. Alors c'est:

$scope.$on('$stateChangeSuccess', function () {
  // do something
});
adam0101
la source
1
Tu es génial, mon ami.
taco
Exactement ce dont j'avais besoin. Je cherchais littéralement cela pendant deux jours!
hellojebus
3
$scope.$on('$routeChangeSuccess'se déclenche à chaque fois que les paramètres de l'url changent (via $locationpar exemple), et donc vous pouvez utiliser juste $scope.$on('$locationChangeSuccess'. Si vous avez besoin d'un déclencheur lors du chargement / rechargement de la page, vous pouvez utiliser $scope.$watch('$viewContentLoaded'comme suggéré ici. Il ne se déclenchera pas lors des changements de paramètres d'URL.
Neurotransmetteur
en utilisant AngularJS 1.17.2, à l'intérieur du contrôleur $ routeChangeSuccess a fonctionné à merveille ... vive adam0101 ...
ArifMustafa
43
angular.element(document).ready(function () {

    // your code here

});
Carlos Trujillo
la source
4
Doit être la réponse acceptée, c'est la façon la plus sûre de le faire
Marwen Trabelsi
C'est bien si nous ne travaillons pas avec $scopeet travaillons plutôt avec this.
Akash
Où cela doit-il aller? Je l'ai dans mon modèle et il ne se déclenche pas.
Dave
Ne serait-il pas préférable d'injecter $ document dans ce cas? angular.element ($ document) .ready ...
jamie
5
Une explication serait appréciée
Hidayt Rahman
32

La solution de Dimitri / Mark n'a pas fonctionné pour moi, mais l'utilisation de la fonction $ timeout semble bien fonctionner pour garantir que votre code ne s'exécute qu'une fois le balisage rendu.

# Your controller, including $timeout

var $scope.init = function(){
 //your code
}

$timeout($scope.init)

J'espère que cela aide.

guico
la source
3
Finalement. C'est le seul qui a fonctionné pour moi. Merci.
zmirc
1
Cela marche. N'oubliez pas non plus d'effacer le timeout avec $ timeout.cancel (timer) où vous avez var timer = $ timeout ($ scope.init, millisecondes); une fois votre initialisation terminée. De plus, je ne pense pas que $ scope devrait avoir une définition 'var' dans votre code ci
Emmanuel NK
Ce devrait être la réponse acceptée. C'était la seule qui fonctionnait pour moi (essayé toutes les réponses ci-dessus). Cela fonctionne même si vous attendez le chargement d'une iframe.
hello_fr1end
Cela marche ! viewcontentLoaded n'a pas fonctionné pour moi
chevalier noir
28

Vous pouvez le faire si vous souhaitez voir l'objet DOM viewContentLoaded changer et faire quelque chose. l'utilisation de $ scope. $ on fonctionne aussi mais différemment, surtout lorsque vous avez un mode de page sur votre routage.

 $scope.$watch('$viewContentLoaded', function(){
    // do something
 });
CodeOverRide
la source
7
Plus précisément, si vous utilisez $ rootScope. $ Watch au lieu de $ rootScope. $ Dessus, il ne se déclenchera pas lors des changements de route, vous pouvez donc utiliser une logique spécifique au chargement de page initial.
csahlman
19

Vous pouvez utiliser l'objet $ window angulaire:

$window.onload = function(e) {
  //your magic here
}
mcgraw
la source
3

Encore une autre alternative si vous avez un contrôleur spécifique à cette page:

(function(){
    //code to run
}());
Chipe
la source
3

Lorsque vous utilisez $ routeProvider, vous pouvez résoudre sur .state et démarrer votre service. C'est-à-dire que vous allez charger Controller et View, seulement après avoir résolu votre service:

ui-routes

 .state('nn', {
        url: "/nn",
        templateUrl: "views/home/n.html",
        controller: 'nnCtrl',
        resolve: {
          initialised: function (ourBootstrapService, $q) {

            var deferred = $q.defer();

            ourBootstrapService.init().then(function(initialised) {
              deferred.resolve(initialised);
            });
            return deferred.promise;
          }
        }
      })

Un service

function ourBootstrapService() {

 function init(){ 
    // this is what we need
 }
}
Leo Lanese
la source
3

Dmitry Evseev a trouvé la réponse assez utile.

Cas 1: Utiliser angularJs seul:
Pour exécuter une méthode au chargement de la page, vous pouvez utiliser ng-initdans la vue et déclarer la méthode init dans le contrôleur, ayant dit que l'utilisation d'une fonction plus lourde n'est pas recommandée, selon les documents angulaires sur ng-init :

Cette directive peut être utilisée abusivement pour ajouter des quantités inutiles de logique dans vos modèles. Il n'y a que quelques utilisations appropriées de ngInit, comme pour aliaser des propriétés spéciales de ngRepeat, comme on le voit dans la démo ci-dessous; et pour injecter des données via des scripts côté serveur. Outre ces quelques cas, vous devez utiliser des contrôleurs plutôt que ngInit pour initialiser des valeurs sur une étendue.

HTML:

<div ng-controller="searchController()">
    <!-- renaming view code here, including the search box and the buttons -->
</div>

Manette:

app.controller('SearchCtrl', function(){

    var doSearch = function(keyword){
        //Search code here
    }

    doSearch($routeParams.searchKeyword);
})

Avertissement: N'utilisez pas ce contrôleur pour une autre vue destinée à une intention différente car cela entraînerait également l'exécution de la méthode de recherche.

Cas 2: Utilisation d'Ionic:
Le code ci-dessus fonctionnera, assurez-vous simplement que le cache de vue est désactivé dans le route.js:

route.js

.state('app', {
    url           : '/search',
    cache         : false, //disable caching of the view here
    templateUrl   : 'templates/search.html'   ,
    controller    : 'SearchCtrl'
  })

J'espère que cela t'aides

Kailas
la source
1
Il n'y en avait qu'un et était tout en bas, content d'avoir fait tout le chemin, il l'a cache: falsefait pour moi - merci!
Rani Kheir
3

J'ai eu le même problème et seule cette solution a fonctionné pour moi (elle exécute une fonction après le chargement d'un DOM complet). J'utilise ceci pour faire défiler pour ancrer une fois la page chargée:

angular.element(window.document.body).ready(function () {

                        // Your function that runs after all DOM is loaded

                    });
Ginko Balboa
la source
2

Vous pouvez enregistrer les résultats de la recherche dans un service commun qui peut être utilisé de n'importe où et ne s'efface pas lorsque vous accédez à une autre page, puis vous pouvez définir les résultats de la recherche avec les données enregistrées pour le clic du bouton Retour

function search(searchTerm) {
    // retrieve the data here;
    RetrievedData = CallService();
    CommonFunctionalityService.saveSerachResults(RetrievedData);
} 

Pour votre backbutton

function Backbutton() {
    RetrievedData = CommonFunctionalityService.retrieveResults();
}
Heshan
la source
0

appeler les méthodes initiales dans la fonction self initialize.

(function initController() {

    // do your initialize here

})();
Uditha Prasad
la source