Cuando cargo una vista, me gustaría ejecutar algún código de inicialización en su controlador asociado.
Para ello, he utilizado la directiva ng-init en el elemento principal de mi vista:
<div ng-init="init()">
blah
</div>
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 forma correcta de hacerlo?
Lo siguiente, tengo un problema con la secuencia de eventos que se producen. En la vista tengo un botón 'save', que utiliza la directiva ng-disabled
como tal:
<button ng-click="save()" ng-disabled="isClean()">Save</button>
la función isClean()
está definida en el controlador:
$scope.isClean = function () {
return $scope.hasChanges() && !$scope.isSaving;
}
Como puedes ver, utiliza la bandera $scope.isSaving
, que fue inicializada 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 que el flag isSaving
está indefinido
. ¿Qué puedo hacer para evitarlo?
Cuando tu vista se carga, también lo hace su controlador asociado. En lugar de utilizar 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();
Como tu controlador se ejecuta antes que ng-init
, esto también resuelve tu segundo problema.
[Fiddle][1]
Como mencionó John David Five
, puede que no quieras adjuntar esto a $scope
para hacer este método privado.
var init = function () {
// do something
}
...
init();
[Ver jsFiddle][2]
Si quieres esperar a que ciertos datos sean preestablecidos, mueve esa solicitud de datos a una resolución o añade un observador a esa colección u objeto y llama a tu método init cuando tus datos cumplan tus criterios init. Yo suelo quitar el observador una vez que se cumplen mis requisitos de datos para que la función init no se vuelva a ejecutar aleatoriamente si los datos que estás observando 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();
}
});
O simplemente puede inicializar en línea en el controlador. Si se utiliza una función init interna al controlador, no es necesario definirla en el ámbito. 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 }
}
Utilizo 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 */ {
// ...
}
});