angularjs restrict directive scope - angularjs

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 = ...
}]
};
})

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

AngularJS: How a Directive without a Controller can work

just reading a write up from this link http://weblogs.asp.net/dwahlin/creating-custom-angularjs-directives-part-6-using-controllers
it was hard me like novice in ng to understand their code sample. just tell me a example where people would write directive without controller ?
their code
(function() {
var app = angular.module('directivesModule');
app.directive('isolateScopeWithController', function () {
var controller = ['$scope', function ($scope) {
function init() {
$scope.items = angular.copy($scope.datasource);
}
init();
$scope.addItem = function () {
$scope.add();
//Add new customer to directive scope
$scope.items.push({
name: 'New Directive Controller Item'
});
};
}],
template = '<button ng-click="addItem()">Add Item</button><ul>' +
'<li ng-repeat="item in items">{{ ::item.name }}</li></ul>';
return {
restrict: 'EA', //Default in 1.3+
scope: {
datasource: '=',
add: '&',
},
controller: controller,
template: template
};
});
}());
Directive usage:
Attribute: <div isolate-scope-with-controller datasource="customers" add="addCustomer()"></div>
Element: <isolate-scope-with-controller datasource="customers" add="addCustomer()"></isolate-scope-with-controller>
How we can pass customer data directly to directive. basically we have model in controller and populate model and then pass that model data to directive via isolated scope or directive use controller scope. I am very confused the how above code can work, please help me to understand. thanks
The scenario that is being considered implies that the directive will be used in a part of the application, that already has a declared controller, the scope of which contains the properties datasource and add. In turn, new controllers will be instantiated for each of the instances of the directive and will have their own isolate scope.
In reality, it is much more common to create directives that do not have a controller, but rather use the link function. These directives can either rely on the parent controller, sometimes perform DOM manipulation, bind to JS events or simply serve as means to encapsulate part of your application.
You can find a good example of a directive that does not create its own controller here. It is taken from the Angular docs. You will find that it does not even belong to a parent scope in this case meaning that no controller is involved. In reality, an element like this would most probably report to a parent controller, which would then do something with the position.
You can read more about directives, the link function, and how directives work with controllers here.

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

How to interact with isolate scope variable within a directive controller?

I have directive myDirective, that has an two-way binding isolate scope. When the user clicks a button, I want to change the isolate scope to be a value. I thought isolate scopes were bound to the $scope, but I am wrong. How do I 'grab' and interact with that isolate scope? Are they not attached to the directive controller's scope?
angular.module("app", [])
.controller("myCtrl", function($scope){
$scope.ctrlTwoway = "Eggs";
})
.directive("myDirective", function(){
return {
scope: {
twoway: =
},
template: "<button ng-click="changeTwoway()">Change two way isolate scope</button>",
controller: function($scope, $element, $attrs){
$scope.changeTwoway = function(){
// get twoway from isolate scope, and update the value with "bacon"
// $scope.twoway = "bacon" doesn't work
// nor does $attrs.twoway = "bacon" work, either :(
};
}
}
});
And the HTML
...
<div my-directive twoway="{{ctrlTwoway}}"></div>
Current value: {{ctrlTwoway}}
I created a plunker with working version.
You don't need to put {{variable}} on on the twoway="". Just change to twoway="ctrlTwoway" to work.
Another thing is that the way that you declare the binding. You are using = instead of '='.
Another thing is: try to use the link function instead of controller function in directives. It's a good practice and the right place if you want to manipulate DOM elements.
Source
I hope it helps.

Resources