angularjs - ejemplo - Problemas con las directivas anidadas angulares al usar ControllerAs
ng-bind (1)
Básicamente, debe usar la opción require
of directive (la opción require
se utiliza para directivas de comunicación con directivas). Lo cual dará acceso a su controlador principal simplemente mencionando la opción require
en la directiva hija. También necesita usar bindToController: true
que básicamente agregará datos de ámbito aislado al controlador de directivas.
Código
function formBuilder() {
return {
restrict: ''A'',
replace: true,
bindToController: true,
scope: {
formData: ''=''
},
templateUrl: ''FormBuilder.html'',
controller: function($scope) {
$scope.formSubmit = function() {
// Submits the formData.formFields and formData.photoFields
// to the server
// The data for these objects are created through
// the child directives below
}
}
}
}
Luego debe agregar la opción require
a las directivas secundarias. Básicamente, la opción require
tendrá la directiva formBuilder
con ^
(indica que formBuilder
estará allí en el elemento padre) como require: ''^formBuilder'',
Al escribir una opción de require
, puede obtener el controlador de esa directiva en el cuarto parámetro de la función de enlace.
Código
function formFields() {
return {
restrict: ''A'',
replace: true,
require: ''^formBuilder'',
templateUrl: ''FormFields.html'',
//4th parameter is formBuilder controller
link: function(scope, element, attrs, formBuilderCtrl){
scope.formBuilderCtrl = formBuilderCtrl;
},
controller: function($scope, $timeout) {
var vm = this;
//getting the `formData` from `formBuilderCtrl` object
//added timeout here to run code after link function, means after next digest
$timeout(function(){
console.log($scope.formBuilderCtrl.formData.formFields);
})
}
}
}
function photoFields() {
return {
restrict: ''A'',
replace: true,
require: ''^formBuilder'',
templateUrl: ''PhotoFields.html'',
//4th parameter is formBuilder controller
link: function(scope, element, attrs, formBuilderCtrl){
scope.formBuilderCtrl = formBuilderCtrl;
},
controller: function($scope, $timeout) {
var vm = this;
console.log(vm.formData.photoFields);
//to run the code in next digest cycle, after link function gets called.
$timeout(function(){
console.log($scope.formBuilderCtrl.formData.formFields);
})
}
}
}
Editar
Un problema con la solución anterior es que, para tener acceso al controlador de la directiva principal en el controlador de directivas, he hecho algunas cosas complicadas. Primero, incluya el formBuilderCtrl
a la variable de ámbito del cuarto parámetro de la función de enlace. Entonces solo usted puede obtener acceso a ese controlador usando $scope
(que no desea allí). Con respecto al mismo problema registrado en Github con estado abierto , puedes verificarlo aquí.
Estoy construyendo una gran forma que llama varias directivas para construir una forma completa. La página principal que llama al generador de formularios pasa los datos del modelo ng así:
<div form-builder form-data=“formData”></div>
Luego, la página de creación de formularios llama a varias directivas para niños para compilar varias secciones del formulario:
FormBuilder.html:
<div form-fields></div>
<div photo-fields></div>
<div video-fields></div>
.. etc.. etc...
Al usar $scope
en el controlador, no tuve ningún problema para acceder al $scope
en las directivas secundarias como esta:
function formBuilder() {
return {
restrict: ''A'',
replace: true,
scope: {
formData: ''=''
},
templateUrl: ''FormBuilder.html'',
controller: function($scope) {
$scope.formSubmit = function() {
// Submits the formData.formFields and formData.photoFields
// to the server
// The data for these objects are created through
// the child directives below
}
}
}
}
function formFields() {
return {
restrict: ''A'',
replace: true,
templateUrl: ''FormFields.html'',
controller: function($scope) {
console.log($scope.formData.formFields);
}
}
}
function photoFields() {
return {
restrict: ''A'',
replace: true,
templateUrl: ''PhotoFields.html'',
controller: function($scope) {
console.log($scope.formData.photoFields);
}
}
}
... etc..
Pero desde que me deshice del $scope
y comencé a usar ControllerAs
, tengo todo tipo de problemas para acceder al enlace bidireccional con Parent-Child Controllers.
function formBuilder() {
return {
restrict: ''A'',
replace: true,
scope: {
formData: ''=''
},
templateUrl: ''FormBuilder.html'',
controller: function() {
var vm = this;
console.log(vm.formData); // Its fine here
vm.formSubmit = function() {
// I cannot change formData.formFields and formData.photoFields
// from Child Directive "Controllers"
}
},
controllerAs: ‘fb’,
bindToController: true
}
}
function formFields() {
return {
restrict: ''A'',
replace: true,
templateUrl: ''FormFields.html'',
controller: function() {
var vm = this;
console.log(vm.formData.formFields);
// No way to access 2 way binding with this Object!!!
}
}
}
function photoFields() {
return {
restrict: ''A'',
replace: true,
templateUrl: ''PhotoFields.html'',
controller: function() {
var vm = this;
console.log(vm.formData.photoFields);
// No way to access 2 way binding with this Object!!!
}
}
}
Cualquier cosa que intento, estoy llegando a un bloque de carreteras. Las cosas que he intentado son:
- Ámbitos aislados: Intenté pasar
formData.formFields
yformData.photoFields
como ámbitos aislados a la directiva hija, pero luego termino obteniendo el error$compile: MultiDir
debido a ámbitos aislados anidados, por lo que no es posible. - Si no tengo directivas individuales para cada sección del formulario y las tengo todas en 1 directiva bajo la directiva
formBuilder
, entonces se convierte en una directiva humillante. Lo anterior es solo un boceto, pero cada directiva para niños construye 1 gran formulario al final. Así que fusionarlos es realmente el último recurso, ya que se vuelve difícil de mantener e ilegible. - No creo que haya una forma de acceder a
ControllerAs
la Directiva Parent deControllerAs
de la Directiva Child de otra manera que lo que he visto hasta ahora. - Si utilizo las ControllerAs de la matriz en el ng-model de la plantilla de la directiva child como
<input type=“text” ng-model=“fb.formData.formFields.text" />
, eso funciona bien, pero necesito acceder a la misma desde el controlador de la directiva Child para algún procesamiento que no puedo hacer. - Si me deshago de los
controllerAs
y uso el$scope
nuevamente, funciona igual que antes, pero estoy tratando de deshacerme del$scope
para prepararme para futuros cambios angulares.
Como es un formulario avanzado, necesito tener una directiva separada para manejar varias secciones de formularios y, dado que los ámbitos anidados no están permitidos desde Angular 1.2, lo hace cada vez más difícil, especialmente cuando se trata de deshacerse de $scope
usando ControllerAs
.
¿Puede alguien guiarme cuáles son mis opciones aquí, por favor? Te agradezco por leer mi larga publicación.