Angular directive second parameter, why is it a function? - angularjs

This is just a general question about Angular directives. Why does angular choose to have a function that returns an object and not just list the object directly as the second parameter?
in other words, why does it look like this:
app.directive('helloWorld', function() {
return {
restrict: 'AE',
replace: 'true',
template: '<h3>Hello World!!</h3>'
};
});
and not this:
app.directive('helloWorld',{
restrict: 'AE',
replace: 'true',
template: '<h3>Hello World!!</h3>'
});

so you can inject dependencies
for example:
app.directive('helloWorld', function($rootScope) {
return {
restrict: 'AE',
replace: 'true',
template: '<h3>Hello World!!</h3>'
};
});
angular will inject the $rootScope into your directive.

Because when you instantiate a directive you want a new instance of it. The function will instantiate a new object for you as opposed to returning the same object.
Additionally the function can also be used for Dependency Injection.

I believe this is to allow for dependency injection ex.
.directive('someDirective', ['$filter', function ($filter) {
'use strict';
return {
restrict: 'A',
require: 'ngModel',
link: function (scope, element, attrs, ngModel) {
});
}
};
}]);

Related

how to start an factory instance inside a init function of angular directive

Inside a directive link function i want to invoke a factory instance, Is it possible
.directive('commentList', function(CommentsService, Global) {
return {
restrict: 'E',
templateUrl: 'xxxx',
link: function($scope, element, attrs) {
....I want to invoke a factory from here
}
}});
.factory('fact'){
}
You can just add fact(factory) at top like this :
.directive('commentList', function(CommentsService, Global, fact) { return { restrict: 'E', templateUrl: 'xxxx', link: function($scope, element, attrs) {
And then by using fact.callFactMethod() something like this from function.

How to invoke a directive by using element name?

I have a angular directive:
app.directive('myDirective', function()
{
return{
restrict: 'AE',
scope: {
myCustomer: "&"
},
require: 'ngModel',
link: function(scope, element, attr, ngModel){
var oldVal;
function fromUser(value){
scope.myCustomer()(value, oldVal);
oldVal = value;
return value;
}
function toUser(value){
return value;
}
ngModel.$parsers.push(fromUser);
ngModel.$formatters.push(toUser);
}
}
}
At the moment I invoke this director by using attribute name and bind it to a function:
<input type="text" my-directive="showInput" ng-model="user.name">
It works fine but what I want is to use element name, something like this:
<my-directive>
The problem is I don't know how to bind to a function as I do with the attributes.
You will need to set 'restrict' to 'E' in your directive definition something like:
bindToController: true,
controller: 'YourController',
controllerAs: 'vm',
restrict: 'E', //<----this is what you want
templateUrl: 'template.html'
You have to pass restrict: 'E' in directive options
angular.module("image-management")
.directive('myDirective', ($modal) => {
return {
restrict: 'E',
scope:{
showInput: '&'
},
template: '',
link: function(){}
})
<my-directive showInput="showInput" ></my-directive>
<my-directive some-function="someFunction"></my-directive>
Then in your directive link function, it is accesible through attr
link: function(scope, element, attr, ngModel){
// Your logic...
attr.someFunction();
}
As #sumair answered, you can do:
<my-directive showInput="showInput" ></my-directive>
But, if you really want to use only
<my-directive>
AND your directive does not require to have an isolated scope, you can just leave the scope property of the directive definition and reference your showInput function directly from inherited scope like so:
app.directive('myDirective', function()
{
return{
restrict: 'AE',
/*scope: { ////// remove this part //////
myCustomer: "&"
},*/
require: 'ngModel',
link: function(scope, element, attr, ngModel){
var oldVal;
function fromUser(value){
scope.showInput()(value, oldVal);
oldVal = value;
return value;
}
function toUser(value){
return value;
}
ngModel.$parsers.push(fromUser);
ngModel.$formatters.push(toUser);
}
}
}

AngularJS - Is it possible to pass attr value in Directive link function directly to template?

I was wondering if its possible to access attrs that were passed into a custom directive directly within the template config? So something like this... which currently isn't working?
angular.module('msDirectives', [])
.directive('msPerson', function(){
return{
restrict: 'E',
link: function(scope, element, attrs){
},
template: '<h1>{{attrs.firstName}}</h1>',
};
});
I realize I could assign attrs.firstName to scope within the link function to get this to work (like the following), just trying to understand whether scope is the only thing accessible within the template or whether attrs also get passed to it.
angular.module('msDirectives', [])
.directive('msPerson', function(){
return{
restrict: 'E',
link: function(scope, element, attrs){
scope.name = attrs.firstName;
},
template: '<h1>{{name}}</h1>'
};
});
The purpose of isolated scope (besides the isolation itself) is the assignment of attribute values to scope.
angular.module('msDirectives', [])
.directive('msPerson', function(){
return{
restrict: 'E',
scope: {
name: '#firstName'
},
template: '<h1>{{name}}</h1>'
};
});

Prevent angular from copying attributes when replace=true

The following directive:
var app = angular.module('demo', []);
app.directive('myDirective', function() {
return {
restrict: 'E',
template: '<h1>Foo bar</h1>'
};
});
With the following usage:
<my:directive foo="bar"></my:directive>
Renders the following HTML:
<my:directive foo="bar"><h1>Foo bar</h1></my:directive>
Since I want to replace my directive with the provided template I set replace:true. This produces the following HTML:
<h1 foo="bar">Foo bar</h1>
Note that Angular copies my directive's attributes to the template elements (the foo="bar"). How can I prevent this behaviour?
You can manually remove the attributes in the link function of the directive:
.directive('myDirective', function() {
return {
restrict: 'E',
replace: true,
template: '<h1>Foo bar</h1>',
link: function(scope, elm, attrs){
elm.removeAttr('foo');
}
};
});
Here's a fiddle with this directive working in your situation.
EDIT: You can extend this to remove all attributes dynamically with a simple loop:
.directive('myDirective', function() {
return {
restrict: 'E',
replace: true,
template: '<h1>Foo bar</h1>',
link: function(scope, elm, attrs){
for(var attr in attrs.$attr){
elm.removeAttr(attr);
}
}
};
});

How can I get my directive to access the controllers scope

I have a setup like this:
<controller>
<directive>
in my controller that has a function that returns an html string. How can I get my directive to render this by accessing the controllers scope?
Or maybe I should just put the controller in the directive?
app.controller('controller', ['$scope', 'DataService', function ($scope, DataService) {
$scope.parseJson = function () {
//returns the html
};
}]);
directive
app.directive('Output', function () {
return {
restrict: 'A',
replace: true,
template: '<need html from controller>',
link: function(scope, element, attr) {
//render
//scope.parseJson();
}
};
});
You should use the isolated scope: '&' option
app.directive('output', ['$sce', function ($sce) {
return {
restrict: 'A',
replace: true,
template: "<div ng-bind-html='parsed'></div>",
scope:{
output: "&"
},
link: function(scope){
scope.parsed = $sce.trustAsHtml(scope.output());
}
};
}]);
Template:
<div output="parseJson()"></div>
The directive and the controller should be sharing the scope already. Don't bother using a template for the directive, just get the HTML string in you linking function (you already have the method call in there) and modify the element directly using element.html(). Take a look at the element docs for more info.
app.directive('Output', function ($compile) {
return {
restrict: 'A',
link: function(scope, element, attr) {
var templateString = scope.parseJson();
var compiledTemplate = $compile(templateString)(scope);
compiledTemplate.appendTo("TheElementYouWishtoAppendYourDirectiveTo");
}
};
});

Resources