data - método de llamada del controlador principal de una directiva en AngularJS
ng-model (4)
Después de mi question anterior, ahora intento llamar un método en el controlador principal de mi directiva. Obtengo un parámetro indefinido. Esto es lo que hago:
<body ng-app="myApp" ng-controller="MainCtrl">
<span>{{mandat.rum}}</span>
<span>{{mandat.surname}}</span>
<input type="text" ng-model="mandat.person.firstname" />
<my-directive mandate-person="mandat.person" updateparent="updatePerson()" >
</my-directive>
</body>
Y el guion:
var app = angular.module(''myApp'', []);
app.controller(''MainCtrl'', function ($scope) {
$scope.mandat = { name: "John", surname: "Doe", person: { id: 1408, firstname: "sam" } };
$scope.updatePerson = function(person) {
alert(person.firstname);
$scope.mandat.person = person;
}
});
app.directive(''myDirective'', function () {
return {
restrict: ''E'',
template: "<div><span>{{mandatePerson.id}}<span><input type=''text'' ng-model=''mandatePerson.firstname'' /><button ng-click=''updateparent({person: mandatePerson})''>click</button></div>",
replace: true,
scope: { mandatePerson: ''='', updateparent: ''&'' }
}
}
)
cuando se llama al método updatePerson, la persona no está definida.
jsfiddle aquí: http://jsfiddle.net/graphicsxp/Z5MBf/7/
Acceder al método del controlador significa acceder a un método en el alcance padre desde el controlador / enlace / alcance de la directiva.
Si la directiva está compartiendo / heredando el alcance principal, entonces es bastante sencillo invocar un método de alcance principal.
Se requiere poco más trabajo cuando desea acceder al método de alcance principal desde el alcance de la directiva aislada.
Hay pocas opciones (pueden estar más que enumeradas a continuación) para invocar un método de alcance principal desde el alcance de directivas aisladas o ver variables de ámbito principal ( opción # 6 especialmente).
Tenga en cuenta que utilicé la link function
en estos ejemplos, pero también puede usar un directive controller
según los requisitos.
Opción 1. A través del objeto literal y de la plantilla directiva html
index.html
<!DOCTYPE html>
<html ng-app="plunker">
<head>
<meta charset="utf-8" />
<title>AngularJS Plunker</title>
<script>document.write(''<base href="'' + document.location + ''" />'');</script>
<link rel="stylesheet" href="style.css" />
<script data-require="[email protected]" src="https://code.angularjs.org/1.3.9/angular.js" data-semver="1.3.9"></script>
<script src="app.js"></script>
</head>
<body ng-controller="MainCtrl">
<p>Hello {{name}}!</p>
<p> Directive Content</p>
<sd-items-filter selected-items="selectedItems" selected-items-changed="selectedItemsChanged(selectedItems)" items="items"> </sd-items-filter>
<P style="color:red">Selected Items (in parent controller) set to: {{selectedItemsReturnedFromDirective}} </p>
</body>
</html>
itemfilterTemplate.html
<select ng-model="selectedItems" multiple="multiple" style="height: 200px; width: 250px;" ng-change="selectedItemsChanged({selectedItems:selectedItems})" ng-options="item.id as item.name group by item.model for item in items | orderBy:''name''">
<option>--</option>
</select>
app.js
var app = angular.module(''plunker'', []);
app.directive(''sdItemsFilter'', function() {
return {
restrict: ''E'',
scope: {
items: ''='',
selectedItems: ''='',
selectedItemsChanged: ''&''
},
templateUrl: "itemfilterTemplate.html"
}
})
app.controller(''MainCtrl'', function($scope) {
$scope.name = ''TARS'';
$scope.selectedItems = ["allItems"];
$scope.selectedItemsChanged = function(selectedItems1) {
$scope.selectedItemsReturnedFromDirective = selectedItems1;
}
$scope.items = [{
"id": "allItems",
"name": "All Items",
"order": 0
}, {
"id": "CaseItem",
"name": "Case Item",
"model": "PredefinedModel"
}, {
"id": "Application",
"name": "Application",
"model": "Bank"
}]
});
plnkr de trabajo: http://plnkr.co/edit/rgKUsYGDo9O3tewL6xgr?p=preview
Opcion 2. A través de Object literal y desde directive link / scope
index.html
<!DOCTYPE html>
<html ng-app="plunker">
<head>
<meta charset="utf-8" />
<title>AngularJS Plunker</title>
<script>document.write(''<base href="'' + document.location + ''" />'');</script>
<link rel="stylesheet" href="style.css" />
<script data-require="[email protected]" src="https://code.angularjs.org/1.3.9/angular.js" data-semver="1.3.9"></script>
<script src="app.js"></script>
</head>
<body ng-controller="MainCtrl">
<p>Hello {{name}}!</p>
<p> Directive Content</p>
<sd-items-filter selected-items="selectedItems" selected-items-changed="selectedItemsChanged(selectedItems)" items="items"> </sd-items-filter>
<P style="color:red">Selected Items (in parent controller) set to: {{selectedItemsReturnedFromDirective}} </p>
</body>
</html>
itemfilterTemplate.html
<select ng-model="selectedItems" multiple="multiple" style="height: 200px; width: 250px;"
ng-change="selectedItemsChangedDir()" ng-options="item.id as item.name group by item.model for item in items | orderBy:''name''">
<option>--</option>
</select>
app.js
var app = angular.module(''plunker'', []);
app.directive(''sdItemsFilter'', function() {
return {
restrict: ''E'',
scope: {
items: ''='',
selectedItems: ''='',
selectedItemsChanged: ''&''
},
templateUrl: "itemfilterTemplate.html",
link: function (scope, element, attrs){
scope.selectedItemsChangedDir = function(){
scope.selectedItemsChanged({selectedItems:scope.selectedItems});
}
}
}
})
app.controller(''MainCtrl'', function($scope) {
$scope.name = ''TARS'';
$scope.selectedItems = ["allItems"];
$scope.selectedItemsChanged = function(selectedItems1) {
$scope.selectedItemsReturnedFromDirective = selectedItems1;
}
$scope.items = [{
"id": "allItems",
"name": "All Items",
"order": 0
}, {
"id": "CaseItem",
"name": "Case Item",
"model": "PredefinedModel"
}, {
"id": "Application",
"name": "Application",
"model": "Bank"
}]
});
plnkr de trabajo: http://plnkr.co/edit/BRvYm2SpSpBK9uxNIcTa?p=preview
Opción # 3. A través de la referencia de función y de la plantilla directiva html
index.html
<!DOCTYPE html>
<html ng-app="plunker">
<head>
<meta charset="utf-8" />
<title>AngularJS Plunker</title>
<script>document.write(''<base href="'' + document.location + ''" />'');</script>
<link rel="stylesheet" href="style.css" />
<script data-require="[email protected]" src="https://code.angularjs.org/1.3.9/angular.js" data-semver="1.3.9"></script>
<script src="app.js"></script>
</head>
<body ng-controller="MainCtrl">
<p>Hello {{name}}!</p>
<p> Directive Content</p>
<sd-items-filter selected-items="selectedItems" selected-items-changed="selectedItemsChanged" items="items"> </sd-items-filter>
<P style="color:red">Selected Items (in parent controller) set to: {{selectedItemsReturnFromDirective}} </p>
</body>
</html>
itemfilterTemplate.html
<select ng-model="selectedItems" multiple="multiple" style="height: 200px; width: 250px;"
ng-change="selectedItemsChanged()(selectedItems)" ng-options="item.id as item.name group by item.model for item in items | orderBy:''name''">
<option>--</option>
</select>
app.js
var app = angular.module(''plunker'', []);
app.directive(''sdItemsFilter'', function() {
return {
restrict: ''E'',
scope: {
items: ''='',
selectedItems:''='',
selectedItemsChanged: ''&''
},
templateUrl: "itemfilterTemplate.html"
}
})
app.controller(''MainCtrl'', function($scope) {
$scope.name = ''TARS'';
$scope.selectedItems = ["allItems"];
$scope.selectedItemsChanged = function(selectedItems1) {
$scope.selectedItemsReturnFromDirective = selectedItems1;
}
$scope.items = [{
"id": "allItems",
"name": "All Items",
"order": 0
}, {
"id": "CaseItem",
"name": "Case Item",
"model": "PredefinedModel"
}, {
"id": "Application",
"name": "Application",
"model": "Bank"
}]
});
plnkr de trabajo: http://plnkr.co/edit/Jo6FcYfVXCCg3vH42BIz?p=preview
Opción # 4. A través de Referencia de función y del enlace / alcance de directiva
index.html
<!DOCTYPE html>
<html ng-app="plunker">
<head>
<meta charset="utf-8" />
<title>AngularJS Plunker</title>
<script>document.write(''<base href="'' + document.location + ''" />'');</script>
<link rel="stylesheet" href="style.css" />
<script data-require="[email protected]" src="https://code.angularjs.org/1.3.9/angular.js" data-semver="1.3.9"></script>
<script src="app.js"></script>
</head>
<body ng-controller="MainCtrl">
<p>Hello {{name}}!</p>
<p> Directive Content</p>
<sd-items-filter selected-items="selectedItems" selected-items-changed="selectedItemsChanged" items="items"> </sd-items-filter>
<P style="color:red">Selected Items (in parent controller) set to: {{selectedItemsReturnedFromDirective}} </p>
</body>
</html>
itemfilterTemplate.html
<select ng-model="selectedItems" multiple="multiple" style="height: 200px; width: 250px;" ng-change="selectedItemsChangedDir()" ng-options="item.id as item.name group by item.model for item in items | orderBy:''name''">
<option>--</option>
</select>
app.js
var app = angular.module(''plunker'', []);
app.directive(''sdItemsFilter'', function() {
return {
restrict: ''E'',
scope: {
items: ''='',
selectedItems: ''='',
selectedItemsChanged: ''&''
},
templateUrl: "itemfilterTemplate.html",
link: function (scope, element, attrs){
scope.selectedItemsChangedDir = function(){
scope.selectedItemsChanged()(scope.selectedItems);
}
}
}
})
app.controller(''MainCtrl'', function($scope) {
$scope.name = ''TARS'';
$scope.selectedItems = ["allItems"];
$scope.selectedItemsChanged = function(selectedItems1) {
$scope.selectedItemsReturnedFromDirective = selectedItems1;
}
$scope.items = [{
"id": "allItems",
"name": "All Items",
"order": 0
}, {
"id": "CaseItem",
"name": "Case Item",
"model": "PredefinedModel"
}, {
"id": "Application",
"name": "Application",
"model": "Bank"
}]
});
plnkr de trabajo: http://plnkr.co/edit/BSqx2J1yCY86IJwAnQF1?p=preview
Opción n. ° 5: a través del ng-model y el enlace bidireccional, puede actualizar las variables padre del ámbito. . Por lo tanto, es posible que no requiera invocar funciones de ámbito principal en algunos casos.
index.html
<!DOCTYPE html>
<html ng-app="plunker">
<head>
<meta charset="utf-8" />
<title>AngularJS Plunker</title>
<script>document.write(''<base href="'' + document.location + ''" />'');</script>
<link rel="stylesheet" href="style.css" />
<script data-require="[email protected]" src="https://code.angularjs.org/1.3.9/angular.js" data-semver="1.3.9"></script>
<script src="app.js"></script>
</head>
<body ng-controller="MainCtrl">
<p>Hello {{name}}!</p>
<p> Directive Content</p>
<sd-items-filter ng-model="selectedItems" selected-items-changed="selectedItemsChanged" items="items"> </sd-items-filter>
<P style="color:red">Selected Items (in parent controller) set to: {{selectedItems}} </p>
</body>
</html>
itemfilterTemplate.html
<select ng-model="selectedItems" multiple="multiple" style="height: 200px; width: 250px;"
ng-options="item.id as item.name group by item.model for item in items | orderBy:''name''">
<option>--</option>
</select>
app.js
var app = angular.module(''plunker'', []);
app.directive(''sdItemsFilter'', function() {
return {
restrict: ''E'',
scope: {
items: ''='',
selectedItems: ''=ngModel''
},
templateUrl: "itemfilterTemplate.html"
}
})
app.controller(''MainCtrl'', function($scope) {
$scope.name = ''TARS'';
$scope.selectedItems = ["allItems"];
$scope.items = [{
"id": "allItems",
"name": "All Items",
"order": 0
}, {
"id": "CaseItem",
"name": "Case Item",
"model": "PredefinedModel"
}, {
"id": "Application",
"name": "Application",
"model": "Bank"
}]
});
plnkr de trabajo: http://plnkr.co/edit/hNui3xgzdTnfcdzljihY?p=preview
Opción # 6: a través de $watch
y $watchCollection
Es un enlace de dos vías para los items
en todos los ejemplos anteriores, si los artículos se modifican en el alcance principal, los artículos en la directiva también reflejarían los cambios.
Si desea ver otros atributos u objetos desde el alcance principal, puede hacerlo usando $watch
y $watchCollection
como se indica a continuación.
html
<!DOCTYPE html>
<html ng-app="plunker">
<head>
<meta charset="utf-8" />
<title>AngularJS Plunker</title>
<script>
document.write(''<base href="'' + document.location + ''" />'');
</script>
<link rel="stylesheet" href="style.css" />
<script data-require="[email protected]" src="https://code.angularjs.org/1.3.9/angular.js" data-semver="1.3.9"></script>
<script src="app.js"></script>
</head>
<body ng-controller="MainCtrl">
<p>Hello {{user}}!</p>
<p>directive is watching name and current item</p>
<table>
<tr>
<td>Id:</td>
<td>
<input type="text" ng-model="id" />
</td>
</tr>
<tr>
<td>Name:</td>
<td>
<input type="text" ng-model="name" />
</td>
</tr>
<tr>
<td>Model:</td>
<td>
<input type="text" ng-model="model" />
</td>
</tr>
</table>
<button style="margin-left:50px" type="buttun" ng-click="addItem()">Add Item</button>
<p>Directive Contents</p>
<sd-items-filter ng-model="selectedItems" current-item="currentItem" name="{{name}}" selected-items-changed="selectedItemsChanged" items="items"></sd-items-filter>
<P style="color:red">Selected Items (in parent controller) set to: {{selectedItems}}</p>
</body>
</html>
script app.js
var app = angular.module(''plunker'', []);
app.directive(''sdItemsFilter'', function() {
return {
restrict: ''E'',
scope: {
name: ''@'',
currentItem: ''='',
items: ''='',
selectedItems: ''=ngModel''
},
template: ''<select ng-model="selectedItems" multiple="multiple" style="height: 140px; width: 250px;"'' +
''ng-options="item.id as item.name group by item.model for item in items | orderBy:/'name/'">'' +
''<option>--</option> </select>'',
link: function(scope, element, attrs) {
scope.$watchCollection(''currentItem'', function() {
console.log(JSON.stringify(scope.currentItem));
});
scope.$watch(''name'', function() {
console.log(JSON.stringify(scope.name));
});
}
}
})
app.controller(''MainCtrl'', function($scope) {
$scope.user = ''World'';
$scope.addItem = function() {
$scope.items.push({
id: $scope.id,
name: $scope.name,
model: $scope.model
});
$scope.currentItem = {};
$scope.currentItem.id = $scope.id;
$scope.currentItem.name = $scope.name;
$scope.currentItem.model = $scope.model;
}
$scope.selectedItems = ["allItems"];
$scope.items = [{
"id": "allItems",
"name": "All Items",
"order": 0
}, {
"id": "CaseItem",
"name": "Case Item",
"model": "PredefinedModel"
}, {
"id": "Application",
"name": "Application",
"model": "Bank"
}]
});
Siempre puede consultar la documentación de AngularJs para obtener explicaciones detalladas sobre las directivas.
Aquí hay otro patrón (funciona en Angular 1.5 ).
angular.module(''module'', [])
.controller(''MyController'', function() {
var self = this;
self.msg = 0;
// implement directive event listener interface
this.onEvent = function(arg) {
self.msg++;
};
})
.directive(''myDirective'', function() {
return {
scope: {
data: ''='',
handler: ''=''
},
template: ''<button ng-click="handler.onEvent(data)">Emit event</button>''
}
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.6/angular.min.js"></script>
<div ng-app="module" ng-controller="MyController as ctrl">
<my-directive handler="ctrl" data="''...received''"></my-directive>
{{ctrl.msg}}
</div>
Hay dos formas con las que podemos llamar usando &
y =
.
Si estoy usando =
para un atributo de alcance , entonces
ng-click=''updateparent({person: mandatePerson})''
será cambiado a
ng-click=''updateparent(mandatePerson)''
Y en la directiva,
updateparent="updatePerson()"
cambiará a
updateparent="updatePerson"
No es necesario mencionar argumentos aquí, se pasarán a la definición de la función del controlador como referencia.
Usar &
se explica en otras respuestas.
Simplemente cambie su html como se muestra a continuación
<my-directive mandate-person="mandat.person" updateparent="updatePerson(person)" >
</my-directive>
no está pasando "persona" con updatePerson es por eso que no está funcionando