AngularJS - accessing the directive object inside the controller - javascript

Let's say that I have define a simple directive:
app.directive('someDirective', [function() {
return {
restrict: 'E',
link: function() {
},
controller: [function() {
// Access directive object here...
}]
}
}]);
Can I access the generated someDirective object inside someDirective's controller function? I know that the this property reference the directive object inside the compile and template functions, but i don't know how to access the directive object inside the controller function. Any tricks?
Thanks.

Sure you can, not sure why you'd want too though...
app.directive('someDirective', [function() {
var directiveObject = {
restrict: 'E',
link: function() {
},
controller: [function() {
// Access directive object here...
directiveObject.whatever
}]
}
return directiveObject;
}]);

Related

Using service inside directive?

I am learning how to create custom directives.
My service looks like that:
myApp.service('myService',function(){
this.myFunction=function(myParam){
// do something
}
});
Here is my directive:
myApp.directive('myDirective',function(myService){
return {
restrict: 'E',
scope: {
param: '=myParam',
},
template: '<button ng-click="myService.myFunction(param)">Do action</button>',
}
});
In HTML, when I use <my-directive my-param="something"></my-directive> it properly renders as a button. However when I click it, myService.myFunction, doesn't get executed.
I suppose I am doing something wrong. Can someone give me a direction?
I guess this has something to do with the directive's scope.
The service wont be available directly inside the template. You'll have to use a function attached to the directive's scope and call the service function from within this function.
myApp.directive('myDirective',function(myService){
return {
restrict: 'E',
scope: {
param: '=myParam',
},
template: '<button ng-click="callService(param)">Do action</button>',
link: function(scope, element, attrs) {
scope.callService = function() {
myService.myFunction();
}
}
}
});
It doesn't work because in your example a directive doesn't actually know what is myService. You have to explicitly inject it e.g.:
myApp.directive('myDirective', ['myService', function(myService){ ... }]);
See also this question or this question.
You should use a controller to do all DOM-modifications.
See this plunkr: https://plnkr.co/edit/HbfD1EzS0av5BG6NgtIv?p=preview
.directive('myFirstDirective', [function() {
return {
'restrict': 'E',
'controller': 'MyFirstController',
'controllerAs': 'myFirstCtrl',
'template': '<h1>First directive</h1><input type="text" ng-model="myFirstCtrl.value">'
};
}
You can inject the service in the controller and then call that function inside your template:
Inject myService into controller:
myApp.controller("ctrl", function($scope, myService) {
$scope.doService = function(myParam) {
return myService.myFunction(myParam);
};
});
Call doService method of the controller inside your template:
myApp.directive('myDirective',function(){
return {
restrict: 'E',
scope: {
param: '=myParam',
},
template: '<button ng-click="doService(param)">Do action</button>',
}
});

How to pass a value into a directives controller in angular?

My directive has a controller and I am trying to figure out how to pass a value from the directive that was passed in. In the example below 'name' is not valid posted to the console but it shows in the html when rendered. Obviously my example is an over simplication, but you get the point.
angular.module('myApp')
.directive('helpLabel', function() {
return {
restrict: 'E',
scope: {
name: '#',
},
template: '<span>{{name}}</span>',
controller: function ($scope) {
console.log(name);
}
};
});
<helpLabel name="test"></helpLabel>
The answer I found is to use bindToController along with controllerAs now effective angular 1.4.
angular.module('myApp')
.directive('helpLabel', function() {
return {
restrict: 'E',
scope:{},
bindToConroller: {
name: '#',
},
template: '<span>{{cntrl.name}}</span>',
controller: function () {
console.log(cntrl.name);
},
controllerAs: "cntrl"
};
});
http://blog.thoughtram.io/angularjs/2015/01/02/exploring-angular-1.3-bindToController.html
This is because when it is being rendered to the html, you encapsulated name within {{}}. If you wan't to access the name property within your directive you have to change your code.
angular.module('myApp')
.directive('helpLabel', function() {
return {
restrict: 'E',
scope: {
name: '#',
},
template: '<span>{{name}}</span>',
controller: function ($scope) {
console.log($scope.name);
}
};
});
In your code, console.log(name);, the variable name is not known your directive and hence not able to access it, but since angular has done binding to 'name' variable, it can render {{name}}.
You should access variable name as $scope.name as variable name is present inside current scope.
Modify your code as follow:
angular.module('myApp')
.directive('helpLabel', function() {
return {
restrict: 'E',
scope: {
name: '#',
},
template: '<span>{{name}}</span>',
controller: function ($scope) {
console.log($scope.name);
}
};
});

How to Create nested objects in isolated scope

So I want to create a nested struture on my nested scope inside a directive like this:
angular.module('myAddress').directive('myAddress', [function () {
return {
restrict: 'AE',
controller: 'myAddressController',
templateUrl: 'my-address.html',
scope: {
address: {
'form': '=addressForm',
'model': '=addressModel'
}
}
};
}]);
But I get an exception that undefined is not a function that I don't get if I remove the address nesting.
How do I put attribute arguments inside a named key on my scope?
Also, If I define $scope.address via the controller it doesn't work as well. But what will execute first? The scope: { 'form' = 'addressForm'} part in my directive or the controller's $scope.form?
With the scope property you define which $scope variables should pass to the directive scope and the type of data-binding.
If you want to create an nested structure within the directive $scope, you could create it in the directive controller function.
For example:
angular.module('myAddress').directive('myAddress', [function () {
return {
restrict: 'AE',
controller: 'myAddressController',
templateUrl: 'my-address.html',
scope: {
addressForm: '=', // Two-way databinding
addressModel: '='
},
controller: function($scope){
$scope.address = {
form: $scope.addressForm,
model: $scope.addressModel
}
},
link: function($scope,$element,$attributes){
//Your code here
}
};
}]);
You can also, define $scope.address in the module controller scope. Then your scope property in the directive should be look like this
scope: {
address: '='
}
UPDATE:
Another question is: Does your directive need an dedicated scope? If not you could set the scope property false. Then your directive can access the $scope variables in your module controller.

Angularjs - how do i access directive attribute in controller

I am new to angularjs and i am stuck in accessing directive attributes in controller.
Directive
<rating max-stars="5" url="url.json"></rating>
app.directive('rating', [function () {
return {
restrict: 'E',
scope: {
maxStars: '=',
url: '#'
},
link: function (scope, iElement, iAttrs) {
console.log(iAttrs.url); //works
}
controller
app.controller('ratingController', ['$scope', '$attrs' , '$http','$routeParams',function ($scope,$attrs,$http,$routeParams) {
console.log($attrs.url); //shows undefined
}]);
How do i access the url attribute in controller?
If you want to associate a controller with a directive, you can use the Directive Definition Object's controller property (either specifying the controller as a function or specifying the name of the controller (in which case it can be registered anywhere in your module)).
app.directive('rating', [function () {
return {
restrict: 'E',
scope: {
maxStars: '=',
url: '#'
},
controller: 'ratingController'
};
});
// Meanwhile, in some other file
app.controller('ratingController', function ($scope, $element, $attrs) {
// Access $attrs.url
// Better yet, since you have put those values on the scope,
// access them like this: $scope.url
...
});
When using two-way data-binding via =, the corresponding attribute's value should not be a literal (because you can't have two-way data-binding to a literal), but a string specifying the name of a property in the current scope.
Using <rating max-stars="5"... together with scope: {maxStars: '='... is wrong.
You hould either use <rating max-stars="5"... and scope: {maxStars: '#'...
or <rating max-stars="someProp"... and scope: {maxStars: '='... while the enclosing scope has a property named someProp with a numeric value (e.g. $scope.someProp = 5;).
app.directive('myDirective',function(){
return{
controller: function($scope,$attrs){
console.dir($attrs);
}
}
});
That's it. If you want to access the elements attributes on a controller, you have to set up a controller for the directive.
(You could however, use a shared service to make those attributes available to another controller, if that's want you want to achieve)
http://jsbin.com/xapawoka/1/edit
Took your code and made a jsBin out of it. I can't see any problems whatsoever, so I'm assuming this is a simple typo somewhere in your code (could be the stray [ bracket at the top of your directive definition).
Here's the code:
var app = angular.module('app', []);
app.controller('ratingController',
function ($scope, $element, $attrs) {
console.log('ctrl.scope', $scope.url);
console.log('ctrl.attrs', $attrs.url);
});
app.directive('rating', function () {
return {
restrict: 'E',
scope: {
maxStars: '=',
url: '#'
},
controller: 'ratingController',
link: function (scope, el, attrs) {
console.log('dir.scope', scope.url);
console.log('dir.attrs', attrs.url);
}
};
});
And here's the output:
http://cl.ly/image/031V3W0u2L2w
ratingController is not asociated with your directive. Thus, there is no element which can hold attributes bound to that controller.
If you need to access those attributes, the link function is what you need (as you already mentioned above)
What exactly do you want to achieve?

Creating an angular directive that binds a service?

Not sure if I am misunderstanding how directives are created here. Say for example I have a controller such as:
angular.module('myApp.controllers').controller('MyController', ['$scope', 'MyService', function($scope, MyService) {
$scope.restangularService = MyService;
}
I then have a directive such as:
angular.module('myApp.directives').directive('myGrid', function() {
return {
restrict: 'A',
templateUrl: 'some/path/here.html',
scope: {
restangularService: '&'
},
controller: ['$scope', function($scope) {
//access $scope.restangularService to run some queries
}
};
});
I then use my directive as such:
<div data-my-grid data-restangular-service='restangularService'></div>
I would expect that in my directive I could access $scope.restangularService and make calls however it's not being populated correctly. Am I doing this totally wrong? Any input? I have a feeling I need to be using the ngModel directive somehow.
The "&" prefix of an isolate scope value in a directive provides "one-way binding" which makes available a getter function in the directive's scope.
Any changes you make to the object will not make their way back up to the parent controller of the directive (it is "read-only"). So you can't access your 'restangularService' variable as you would in the controller's scope, without calling the getter function:
angular.module('myApp.directives', []).directive('myGrid', function() {
return {
restrict: 'A',
templateUrl: 'some/path/here.html',
scope: {
restangularService: '&'
},
controller: ['$scope', function($scope) {
console.log($scope.restangularService()); // outputs service value
}]
};
})
Alternatively, you could use "=", which would allow you directly access the scope object you pass in:
angular.module('myApp.directives', []).directive('myGrid', function() {
return {
restrict: 'A',
templateUrl: 'some/path/here.html',
scope: {
restangularService: '='
},
controller: ['$scope', function($scope) {
console.log($scope.restangularService); //outputs service value
}]
};
})
Plunk demonstrating both types

Categories