Ejecutando el código de inicialización de AngularJS cuando se carga la vista

Cuando cargo una vista, me gustaría ejecutar algún código de inicialización en su controlador asociado.

Para hacerlo, he usado la directiva ng-init en el elemento principal de mi vista:

blah

y en el controlador:

 $scope.init = function () { if ($routeParams.Id) { //get an existing object }); } else { //create a new object } $scope.isSaving = false; } 

Primera pregunta: ¿es esta la manera correcta de hacerlo?

A continuación, tengo un problema con la secuencia de eventos que tiene lugar. En la vista, tengo un botón ‘guardar’, que usa la directiva ng-disabled como tal:

  

La función isClean() se define en el controlador:

 $scope.isClean = function () { return $scope.hasChanges() && !$scope.isSaving; } 

Como puede ver, usa el $scope.isSaving , que se inicializó en la función init() .

PROBLEMA: cuando se carga la vista, se llama a la función isClean antes de la función init() , por lo tanto, la bandera isSaving undefined está undefined . ¿Qué puedo hacer para prevenir eso?

Cuando su vista se carga, también lo hace su controlador asociado. En lugar de usar ng-init , simplemente llame a su método init() en su controlador:

 $scope.init = function () { if ($routeParams.Id) { //get an existing object } else { //create a new object } $scope.isSaving = false; } ... $scope.init(); 

Dado que su controlador se ejecuta antes de ng-init , esto también resuelve su segundo problema.

Violín


Como mencionó John David Five , es posible que no desee adjuntar esto a $scope para que este método sea privado.

 var init = function () { // do something } ... init(); 

Ver jsFiddle


Si desea esperar a que se preestablezcan ciertos datos, mueva esa solicitud de datos a una resolución o agregue un observador a esa colección u objeto y llame a su método init cuando sus datos cumplan sus criterios de inicio. Normalmente elimino el monitor una vez que se cumplen mis requisitos de datos, por lo que la función de inicio no se vuelve a ejecutar aleatoriamente si los datos que miras cambian y cumplen tus criterios para ejecutar tu método init.

 var init = function () { // do something } ... var unwatch = scope.$watch('myCollecitonOrObject', function(newVal, oldVal){ if( newVal && newVal.length > 0) { unwatch(); init(); } }); 

Desde AngularJS 1.5 deberíamos usar $onInit que está disponible en cualquier componente AngularJS. Tomado de la documentación del ciclo de vida de los componentes desde la v1.5 es la forma preferida:

$ onInit (): se invoca en cada controlador después de que todos los controladores en un elemento hayan sido construidos y se hayan inicializado sus enlaces (y antes de las funciones de enlace previo y posterior para las directivas sobre este elemento). Este es un buen lugar para poner código de inicialización para su controlador.

 var myApp = angular.module('myApp',[]); myApp.controller('MyCtrl', function ($scope) { //default state $scope.name = ''; //all your init controller goodness in here this.$onInit = function () { $scope.name = 'Superhero'; } }); 

>> Fiddle Demo


Un ejemplo avanzado de uso del ciclo de vida de los componentes:

El ciclo de vida de los componentes nos da la capacidad de manejar cosas de componentes de una buena manera. Nos permite crear eventos para, por ejemplo, “init”, “change” o “destroy” de un componenent. De esa manera, podemos administrar cosas que dependen del ciclo de vida de un componente. Este pequeño ejemplo muestra para registrar y anular el registro de $rootScope event listener $on . Al saber que un evento $on binded en $rootScope no se desincorporará cuando el controlador pierda su referencia en la vista o se destruya, tenemos que destruir $rootScope.$on listener manualmente. Un buen lugar para poner esas cosas es $onDestroy la función del ciclo de vida de un componente:

 var myApp = angular.module('myApp',[]); myApp.controller('MyCtrl', function ($scope, $rootScope) { var registerScope = null; this.$onInit = function () { //register rootScope event registerScope = $rootScope.$on('someEvent', function(event) { console.log("fired"); }); } this.$onDestroy = function () { //unregister rootScope event by calling the return function registerScope(); } }); 

>> Demo Fiddle

O simplemente puede inicializar en línea en el controlador. Si usa una función init interna al controlador, no necesita ser definida en el scope. De hecho, puede ser autoejecutable:

 function MyCtrl($scope) { $scope.isSaving = false; (function() { // init if (true) { // $routeParams.Id) { //get an existing object } else { //create a new object } })() $scope.isClean = function () { return $scope.hasChanges() && !$scope.isSaving; } $scope.hasChanges = function() { return false } } 

Uso la siguiente plantilla en mis proyectos:

 angular.module("AppName.moduleName", []) /** * @ngdoc controller * @name AppName.moduleName:ControllerNameController * @description Describe what the controller is responsible for. **/ .controller("ControllerNameController", function (dependencies) { /* type */ $scope.modelName = null; /* type */ $scope.modelName.modelProperty1 = null; /* type */ $scope.modelName.modelPropertyX = null; /* type */ var privateVariable1 = null; /* type */ var privateVariableX = null; (function init() { // load data, init scope, etc. })(); $scope.modelName.publicFunction1 = function () /* -> type */ { // ... }; $scope.modelName.publicFunctionX = function () /* -> type */ { // ... }; function privateFunction1() /* -> type */ { // ... } function privateFunctionX() /* -> type */ { // ... } });