Get parent controller scope into directive using controller instead of link - angularjs

I am using a 'LocalCtrl' controller for all functionality needed for directive, but how do i get scope of parent controller into the directive and scope from directive back to controller.
My directive is embedded in parent controller. I know how to use link function and isolate scope for two way binding between directive and controller. I'm not sure how to inherit parent scope by using the following structure.
<div ng-controller = "mainCtrl">
<my-directive></my-directive>
</div>
app.controller('mainCtrl',function ($scope) {
$scope.mainContent = "this is main content"
});
app.controller('LocalCtrl',function () {
var vm = this;
vm.content = "This is Header"
});
app.directive('mydirective',function () {
return{
controller:'LocalCtrl as local',
templateUrl: '<div>{{local.content}}</div>',
}
});

Directives in Angularjs has 3 scopes , as mentioned below
refer In which cases angular directive scope equals controller scope?
1 . By default , scope is false , which incase on change of the scope variable in your directive also changes the parents scope variable as it doesn't create a new scope.
app.directive('mydirective',function () {
return{
controller:'LocalCtrl as local',
templateUrl: '<div>{{local.content}}</div>',
}
});
scope:true , With this it will create a new child scope in child directive , which inherits prototypically from the parent scope or parents controller scope
app.directive('mydirective',function () {
return{
scope:true,
controller:'LocalCtrl as local',
templateUrl: '<div>{{local.content}}</div>',
}
});
3: scope:{} : isolate scope , which doesn't inherit from parent's scope (could create re-usable components/directives)
view
<div ng-controller = "mainCtrl ">
<my-directive content="mainContent" some-fn="someFn"></my-directive>
</div>
app.directive('mydirective',function () {
return{
scope:{
twoWayConent:'=content',// two way data binding
oneWayConent:'#conent', // one way binding
someFn:'&someFn' //function binding ( 2 way)
},
controller:'LocalCtrl as local',
templateUrl: '<div>{{local.content}}</div>',
}
});
4. using require: : if you have one directive in another directive ,In Directive Defination object (DDO) require can be used to access the parents directive controllers variables and functionalities in your child directive as below
view
<parent-directive>
<child-directive></child-directive>
</parent-directive>
app.directive('childDirective',function () {
return{
require:'^parentDirective' // can be array of parents directive too
link:function(scope,element,attrs,parentDirectiveController){
console.log(parentDirectiveController) // can access parent directive controllers instances
}
}
});

Related

angularjs restrict directive scope

I have three controllers, one parent and two nested controllers that are siblings in the DOM. All contain a property called "customisation". The two nested controllers use a directive that creates/binds a DOM element to the "customisation" property. My issue, is that a change to the value of the bound DOM property in one nested controller is changing the value in it's sibling nested controller.
I'm assuming it is something to do with the scope of the directive. I wish to restrict the scope of the directive to the individual controller so as not to affect the parent controller or any siblings.
Any advice please?
You can specify the controller in you directive.
app.directive( 'directive', function () {
return {
controller: 'CtrlName'
};
});
Or you can create your own scope for the directive.
app.directive('directive', function() {
return {
scope: {},
controller: ['$scope', function($scope) {
$scope.customisation = ...
}]
};
})

Make child scope same as parent isolated scope

I would like to make a directive that has an isolated scope.
Within this directive are some other directives and those should have the same scope as it parent.
<parent> <!-- Isolated scope -->
<child> </child> <!-- Belongs to the container isolated scope -->
</parent>
I'm not able to make this happen.
Edit
this Plunker shows how children keeps the same scope as it parent if parent is a child scope. I forgot, when you don't use a template/templateUrl, data inside the element will not be thrown away.
It seems that children's scope can't be the same as parent scope if parent scope is isolated. Require is needed to add data to the parent scope.
It's because of ngTransclude. In the docs (https://docs.angularjs.org/guide/directive) it states:
The transclude option changes the way scopes are nested. It makes it
so that the contents of a transcluded directive have whatever scope is
outside the directive, rather than whatever scope is on the inside. In
doing so, it gives the contents access to the outside scope.
Have you tried using the require property on your child directive definition object? You will need to define a controller on your parent and with the require property set to ^container in the child directive you will then have access to the parent controller in your link function as the fourth argument:
angular.module('app', [])
.directive('container', function(){
return {
restrict : 'E',
transclude : true,
scope : {
},
template : 'container <ng-transclude> </ng-transclude>',
controller: function($scope){
// use this to add properties to the controller itself
// which you can then access in the child directive
this.container = "container";
},
link : function($scope){
}
};
})
.directive('child', function(){
return {
require: '^container',
restrict : 'E',
template : 'child container',
link : function($scope, element, attrs, containerController){
$scope.child = "child";
// logs: containerController Object {container: "container"}
console.log('containerController', containerController);
}
};
});

AngularJS - exposing controller api to directive

How do I make controller functions visible to a directive? Do I attach the methods to the scope, and inject the scope into the directive? Is it a good idea in the first place? I want to manipulate model data from within the UI.
It really dependes on what you want to do.
Since you want to access the controller's scope from the directive, I suggest you declare your directive with it's scope shared with the parent controller by setting it's scope prop to false:
app.directive('directiveName', function() {
scope: false,
link: function(scope) {
// access foo from the controler's scope
scope.foo;
}
});
This is a nice example with how directives can be hooked up to a controller
http://jsfiddle.net/simpulton/GeAAB/
DIRECTIVE
myModule.directive('myComponent', function(mySharedService) {
return {
restrict: 'E',
controller: function($scope, $attrs, mySharedService) {
$scope.$on('handleBroadcast', function() {
$scope.message = 'Directive: ' + mySharedService.message;
});
},
replace: true,
template: '<input>'
};
});
HOOKUP IN CONTROLLER
sharedService.broadcastItem = function() {
$rootScope.$broadcast('handleBroadcast');
};
VIEW
<my-component ng-model="message"></my-component>
Adding to #grion_13 answer, scope:true would also work since it creates a new scope that is child of the parent scope so has access to parent scope data.
But a true reusable directive is one which get it input data using isolated scope. This way as long as your html+ controller can provide the right arguments to the directive isolated scope, you can use the directive in any view.

can a custom directive have both an isolated scope AND a "controller: ctrlName" field?

If a directive has an isolated scope, will the controller field be taken into account ?
If yes, how does exactly the directive access this controller ?
Yes, the isolated scope has nothing to do with the controller. Your problem is more of how to work with the controller (it use doesn't change in regard of the scope type).
A controller is useful when you want a directive to be required. If you have a directive called menu and another directive called menu-item and you want for example register all your menu-item in the menu directive, you create a controller.
When your menu-item does a require: 'menu' what it requires is the menu controller, not the directive itself.
Then you can have a directive like:
angular.module('app').directive('menu', function() {
return {
scope: {},
controller: function($scope) {
$scope.foo = "foo";
this.register = function(scope) {
// register child here
};
}
});
$scope.foo can be accessed by menu template, but this.register can't.
When you require menu in your menu-item you can't access $scope.foo but you can access this.register.
TL;DR; Scope type and having a controller are not related.
Example: http://plnkr.co/edit/fzbSnhxN9rp4Ct5kvB9i?p=preview

angularjs ng-class in nested directive

Tried so many different ways and still can't figure this. I have a menu with ng-class="{menuVisibleAnimation: menuOpen}" in a template in a nested directive. When I click on the button in the parent directive I want to change the value of menuOpen to true but the menu in the child directive is not updating?
http://plnkr.co/edit/nOunKkch0Gt8hjMWtruA?p=preview
The main issue in your implementation is that you want to use the the $scope to share the value of menuOpen between the parent and child directive, but your parent directive has an isolated scope :
scope: {
menuOpen: '#menuOpen'
}
You need to declare menuOpen in a scope shared by both directives, due to transclusion it has to be the parent scope of the parent directive. So, in the parent directive you should not create a new scope :
scope: false,
link: function($scope) {
$scope.menuOpen = false;
$scope.toggleMenu = function() {
$scope.menuOpen = !$scope.menuOpen;
};
}
Then, openMenu is accessible in the child directive. See it in in a fork of your Plunker.

Resources