I have a directive that has a transclude. The transcluded content is a form which has a submit option calling a method in the (parent) controller. This method is called from the transcluded scope so any variables I access in the controller I can access via this.variable
as this reflects the callers (current) scope. However, $scope.variable
is undefined as $scope
is that of the parent scope, which is the scope of the controller.
Should I indeed use this
to access the forms values or is there a convention that I should implement to access via $scope
in the (parent) controller?
Disclaimer: I know I'm not using controllerAs functionality, and right now I am not able to change that for the project.
Plunker to demonstrate the issue: http://plnkr.co/edit/TdgZFIRNbUcHNfe3a7uO?p=preview
As you can see the value inside the directive updates when you change the value in the textbox. This is as expected as both refer to the transcluded scope. The {{name}}
outside the directive does not change as this is the parent scope and not the transcluded scope. One-way traffic.
What is the proper solution? Use this.name
or modify the directive so that $scope.name
can be used outside the directive?
For those who like code over plunkers:
HTML:
<body ng-app="docsTransclusionExample">
<div ng-controller="Controller">
{{name}}
<my-dialog>
Check out the contents, {{name}}!
<form>
<input ng-model="name">
</form>
</my-dialog>
</div>
</body>
Directive:
(function(angular) {
'use strict';
angular.module('docsTransclusionExample', [])
.controller('Controller', function($scope) {
$scope.name = 'Tobias';
})
.directive('myDialog', function() {
return {
restrict: 'E',
transclude: true,
scope: {},
templateUrl: 'my-dialog.html'
};
});
})(window.angular);
Directive template:
<div class="alert" ng-transclude></div>
This is related to "The Dot Rule" in angular.
This means, that when you have scope heirarchy, and a child scope is trying to modify a parent scope, it's creating it's own scope.
When you use data objects, you access members "with a dot", and so you don;t change the scope directly, and not creating a new child scope
In your case
$scope.name = 'Tobias';
shuold change to
$scope.data = {name: 'Tobias'};
see plunker: http://plnkr.co/edit/RqORVm8r4jph532dT6nY?p=preview
for further reading:
Why don't the AngularJS docs use a dot in the model directive?
https://www.youtube.com/watch?v=DTx23w4z6Kc
PS.
scope: {}
in directive, you explicitally create a child scope.