Creating an angular directive that binds a service? - javascript

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

Related

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

AngularJS - accessing the directive object inside the controller

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

$scope not being injected/inherited from controller to directive with dot notation

I'm having an issue with injecting/inheriting a scope from a controller to a directive. Importantly, the module is not separated into its own var.
angular.module('articles').controller('ArticlesController', ['$scope, ...
]).directive('comments', ['$scope' ... //does not work!
You don't inject the scope into a directive as a dependency. Should be like this:
.directive([function() {
return {
"link": function($scope, $element, $attrs) {
//code here
}
}
}]);
The best way is to think about directives as black boxes. You provide it with some data and it updates/displays it. You can read all required info about directives here and declare directive's inputs and outputs like this:
.directive('myDirective', function() {
return {
restrict: 'E',
scope: {
myParameter: '=' //this declares directive's interface (2 way binded)
},
link: function (scope, element) {
console.log(scope.myParameter);
}
};
});
and then you can use this directive as:
<my-directive my-parameter='variable_declared_in_controller'></my-directive>
I just bypassed $scope entirely with a couple of other scopes:
.directive('comments', ['$stateParams', '$location', 'Articles',
function ( $stateParams, $location, Articles) {
if ($stateParams.articleId != null){
var article = Articles.get({
articleId: $stateParams.articleId
});
var comments = {articleId: article.articleId, created: Date.now, comment:"Hello, World!", user: "admin" };
return{
restrict: "A",
scope: true,
template: "<div></div>"
};
}
}
]);

Get parent directive controller in child directive

I have the following directive:
angular.module('test').directive('childDirective', [function() {
return {
restrict: 'E',
require: '^parentDirective',
controller: function() {
// How do I get parentDirective's controller?
},
link: function($scope, $element, $attrs, $controller) {
var data = $controller.parentDirectiveData;
....
....
}
};
}]);
In the link function I get $controller dependency that holds a reference to parentDirective's controller. How do I get that reference in childDirective's controller?
You have a couple of options, you can either put it on the scope, or store it in a variable that the controller can access also:
angular.module('test').directive('childDirective', [function() {
var parentCtrl;
return {
restrict: 'E',
require: '^parentDirective',
controller: function() {
// parentCtrl will be defined after the link function runs.
},
link: function($scope, $element, $attrs, $controller) {
var data = $controller.parentDirectiveData;
parentCtrl = $controller
}
};
}]);
Importantly please note that the controller function will run before the link function, so you can only really use this in async callbacks.
There is no way to inject the instance of the parent's controller into the child controller before this, because it relies on the directives being bound to the scope in order for that hierarchy to be defined.

What's the best way to call function within directive from controller

Just wondering what's the best way to communication from controller to directive function, i have got an ng-click on one of the button, but the function sit in the directive, is there a way i can call the function within the controller (which sits in directive). i understand u can apply double binding with scope, is there any better way of doing so?
Cheers
app.controller('leadsListing', ['$scope', function($scope){
$scope.filterresultcount = 0;
$scope.records = [];
$scope.filtertotal = '';
$scope.$watch('filtertotal', function(){
$scope.filterresultcount = parseInt($scope.filtertotal / 20);
});
$scope.moreFilterResult = function(){
if($scope.filterresultcount > 0){
$scope.filterresultcount--;
}
$scope.heyJoe(); // It's in diretive
};
}]);
app.directive('recordfilter', ['$http', 'filterService', function($http, filterService){
return {
scope: {
names : '#names',
model : '#model',
records : '=records',
filtertotal : '=filtertotal',
filterresultcount : '=filterresultcount'
},
restrict: 'A',
replace: true,
link: function($scope, iElm, iAttrs, controller) {
$scope.heyJoe()
}
}
}
I believe the best way to implement this kind of controller --> directive communication is to use $scope.$broadcast from the controller, and $scope.$on in the directive's controller/ linking function.
Controller:
app.controller('leadsListing', ['$scope', function($scope){
// ...
$scope.moreFilterResult = function(){
if($scope.filterresultcount > 0){
$scope.filterresultcount--;
}
$scope.$broadcast('joeCalled');
};
}]);
Directive:
app.directive('recordfilter', ['$http', 'filterService', function($http, filterService){
return {
scope: {
names : '#names',
model : '#model',
records : '=records',
filtertotal : '=filtertotal',
filterresultcount : '=filterresultcount'
},
restrict: 'A',
replace: true,
link: function(scope, iElm, iAttrs, controller) {
scope.$on('joeCalled', function(){
// Do something...
});
});
};
}
Edit:
Created a working example of this technique:
http://jsfiddle.net/9p3eyy5h/2/
Calling a function directly in the directive from the controller could be done by placing an empty object on the controller scope, binding it to the directive's scope with '=', and attaching a function to it in the directive's linking function/ controller, which could later be called by the wrapping controller.
Controller:
app.controller('leadsListing', ['$scope', function($scope){
// ...
$scope.directiveFuncs = {};
$scope.moreFilterResult = function(){
if($scope.filterresultcount > 0){
$scope.filterresultcount--;
}
$scope.directiveFuncs.heyJoe();
};
}]);
Directive:
app.directive('recordfilter', ['$http', 'filterService', function($http, filterService){
return {
scope: {
names : '#names',
model : '#model',
records : '=records',
filtertotal : '=filtertotal',
filterresultcount : '=filterresultcount',
// Binding to the controller's func obj
funcs: '='
},
restrict: 'A',
replace: true,
link: function(scope, iElm, iAttrs, controller) {
scope.funcs.heyJoe = function(){
// Do something...
}
});
};
}
HTML:
<div ng-controller="leadsListing">
<div recordfilter funcs="directiveFuncs"></div>
</div>
I would however advise to use my other approach, as it prevents direct dependency between the controller and the directive, and therefor, more robust, so it won't throw an error if the directive is missing or changes.
Working example:
http://jsfiddle.net/9pm3zg5s/1

Categories