angularjs ng-class in nested directive - angularjs

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.

Related

Get parent controller scope into directive using controller instead of link

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
}
}
});

Target ng-if outside controller

I have a feedback feature on my app,
#feedback
%h3.button
%a{"ui-sref" => ".feedback", "ng-click" => "feedbackActive=!feedbackActive;"}
Feedback
#feedback-container{"ng-if" => "feedbackActive"}
%div{"ui-view" => "feedback"}
The #feedback-container has a ng-if so that the content is only loaded when needed. The %a has a ng-click that toggles between true/false for the the feedbackActive state.
This works fine. Howoever in my ui-view I load a template. In that template is a send button that has a send() function linked to the feedbackCtrl,
$scope.send = function(){
console.log ('send')
console.log ($scope.feedbackForm)
createFeedback.create({
name: $scope.feedbackForm.name,
feedback: $scope.feedbackForm.feedback
})
$scope.feedbackActive = false;
}
It runs the code fine, but doesn't give the feedbackActive the false value so nothing happens.
How do remove toggle the ng-if from outside the controller?
This is a classic scoping issue. Your controller's scope is a child of the scope of the ng-if directive. One option is to use $scope.$parent to set the variable on the parent scope.
$scope.send = function(){
console.log ('send')
console.log ($scope.feedbackForm)
createFeedback.create({
name: $scope.feedbackForm.name,
feedback: $scope.feedbackForm.feedback
})
$scope.$parent.feedbackActive = false;
}
The other option is to take advantage of prototypical inheritance. In the parent controller, initialize an object.
$scope.x = {}; //parent scope
In the view controller, set properties on the inherited object.
$scope.x.feedbackActive = false; //child scope
And of course in your HTML
<feedback-container ng-if="x.feedbackActive">

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);
}
};
});

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

Resources