difference between isolated scope + binding name and isolated scope only in AngularJS - javascript

i'm learning directives in AngularJS, and found that in a few examples, when adding an isolated scope (#, = or &). They sometimes add not only the isolated scope, but also the ngModel name after it. i.e.: "#name" instead of only "#".
So what's the difference between:
myApp.directive('zippy', function() {
return {
restrict: "E",
transclude: true,
replace: true,
scope: {
name: "#" // <----
},
template: "<div>{{name}}<div ng-transclude></div></div>",
link: function(scope, element, attrs) {
console.log(scope.name);
}
}
});
And this:
myApp.directive('zippy', function() {
return {
restrict: "E",
transclude: true,
replace: true,
scope: {
name: "#name" // <----
},
template: "<div>{{name}}<div ng-transclude></div></div>",
link: function(scope, element, attrs) {
console.log(scope.name);
}
}
});

This is from the developer guide
For cases where the attribute name is the same as the value you want
to bind to inside the directive's scope, you can use this shorthand
syntax:
...
scope: {
// same as '=customer'
customer: '='
},
...
Means you can use name: "#" in your directive if your have same name html attribute where directive is declared
<div zippy name="myName"></div>
Remember attribute name should match not the expression in the attribute. It can be any property on scope.

Related

how to pass multiple scope variables into custom directive in angularjs

I am trying to pass 2 scope variables from controller into a custom directive and having problem in accessing both of them.Model is same for the directive and controller.
Here is the code:
Html:
<myDirective data="var1" item="var2"></myDirective>
Controller:
$scope.var1="abc";
$scope.var2="xyz";
Directive:
app.directive('myDirective', function () {
return {
restrict: 'E', //E = element, A = attribute, C = class, M = comment
scope: {
var1: '='
var2:'='
},
templateUrl: 'myTemplate.html',
link: function ($scope, element, attrs) {
}
}
});
TemplateUrl: myTemplate.html
<div>{{var1}}</div> // This works
<div>{{var2}}</div> // This doesn't works
Any idea how can I use both?
Make these changes in your code
<popover data="var1" item="var2"></popover>
JS
app.directive('popover', function () {
return {
restrict: 'E', //E = element, A = attribute, C = class, M = comment
scope: {
data: '=',
item: '='
},
templateUrl: 'myTemplate.html',
link: function (scope, element, attrs) {
console.log(scope.data, scope.item);
}
}
});
Change your template to match the names declared in the DDO.
<myDirective var1="var1" var2="var2"></myDirective>
Avoid using data as an attribute name. That is a reserved prefix that is stripped during normalization. For more information on attribute normilization, see AngularJS Developer Guide - Directive Normilization.

Passing Object to directive through attribute and containing variable

I wanna transfer a $scope.data to directive through its attribute in a Object, Can I achieve below format with any solution but not through separated attribute?
<custom-directive detail="{index:1, data: {{data}}}">
</custom-directive>
And the scope is set to below in directive
scope: {detail: "="}
One solution could be
return {
restrict: 'E',
require: 'ngModel',
scope: {
model: '=ngModel',
},
link: function(scope, element, attributes, ngModel) {
if (!ngModel) {
return;
}
console.log(scope.model); // your passed data
}
}
and then
<custom-directive ngModel="data"></custom-directive>
Now you will have your $scope.data passed to the directive inside scope.model. But note that, any change in scope.model in directive will reflect in $scope.data too.
To avoid that, you can simpley change ngModel.
return {
restrict: 'E',
scope: {
data: '=myData',
},
link: function(scope, element, attributes) {
console.log(scope.data); // your passed data
}
}
and then
<custom-directive my-data="data"></custom-directive>
You just write data only in your object, it will automatically resolves from your controller. Do as below:
HTML
<custom-directive detail="{index:1, data: data}">
</custom-directive>
Directive
myApp.directive('customDirective', function() {
return {
restrict:"AE",
scope:{
detail:"="
},
link:function(scope,ele,attrs) {
alert(JSON.stringify(scope.detail));
}
}
});
Fiddle Demo
You still have the solution to create your object in your controller :
$scope.detail = {index:1, data:$scope.data};
and to give it to your directive :
<custom-directive detail="detail"></custom-directive>

How to make two way binding between angular directives without using "dots"

Suppose, I have controller:
angular.module('tf').controller('Ctrl', function($scope){
$scope.params = {
orderBy: null
};});
And a directive "common":
angular.module('tf').directive("common", function() {
return {
restrict: 'E',
replace: true,
template: '<div><outer order-by="orderBy"><inner order-by-field="name1"></inner><inner order-by-field="name2"></inner></outer></div>',
controller: function ($scope) {
},
scope: {
orderBy: '='
},
link: function (scope, element, attrs) {
}
}});
Controller is using directive within it's template:
<div ng-app="tf">
<div ng-controller="Ctrl">
<common order-by="params.orderBy"></common>
<div style="color:red">{{params.orderBy}}</div>
</div>
This directive is using directive "outer":
angular.module('tf').directive("outer", function() {
return {
restrict: 'E',
transclude: true,
replace: true,
template: '<div ng-transclude></div>',
controller: function ($scope) {
this.order = function (by) {
$scope.orderBy = by
};
},
scope: {
orderBy: '=',
}
}});
Which is parent for the directive "inner":
angular.module('tf').directive("inner", function() {
return {
require: '^outer',
restrict: 'E',
transclude: true,
replace: true,
template: '<div ng-click="onClicked()">{{orderByField}}</div>',
controller: function ($scope) {
$scope.onClicked = function () {
$scope.outer.order($scope.orderByField);
}
},
scope: {
orderByField: '#'
},
link: function (scope, element, attrs, outer) {
scope.outer = outer;
}
}});
The directive "outer" shares "order" method with directive "inner" by it's controller. The directive "inner" is accessing it by using "require" mechanism.
For some reason, this is not working as expected (Property of the controller isn't updated each time it's changed by directive). If I place "orderBy" into object (e.g. {"order": {"by": null }} ) and use object instead of string value, everything is working as expected ( controller scope is properly updated by the directive). I know about "always use dots" best practices principle, but I don't wanna use it here, because it would make my directive's API less intuitive.
Here is jsfiddle:
http://jsfiddle.net/A8Vgk/1254/
Thanks

Angular JS directive, change a 2 way data binding in the link function

I'm trying to create an angular directive where I can set the options either via a single options object, or via some attributes. Here is an example of the kind of code:
app.directive('testElement', [function () {
return {
restrict: "E",
scope: {
options: "="
},
template: "<p><span>Name: </span>{{ options.name }}</p>",
link: function (scope, element, attrs) {
scope.options = scope.options || {};
if (attrs.name)
scope.options.name = attrs.name;
}
};
}]);
This works fine, in that the name value is displayed if I pass in a name via the options attribute. But if I pass a name via the name attribute, even though the link function does modify options, the value is not rendered.
http://plnkr.co/edit/IMVZRdAW2a5HvSq2WtgT?p=preview
I feel like I'm missing something fundamental in how the 2 way data binding of options works.
If you don't pass the two way data binding, angular gets angry:
https://github.com/angular/angular.js/issues/1435
Use optional binding (=?):
app.directive('testElement', [function () {
return {
restrict: "E",
scope: {
options: "=?"
},
template: "<p><span>Name: </span>{{ options.name }}{{ test }}</p>",
link: function (scope, element, attrs) {
scope.options = scope.options || {};
if (attrs.name)
scope.options.name = attrs.name;
}
};
}]);
Or if you are using an older version of angular, use $eval on attrs. options:
app.directive('testElement', [function () {
return {
restrict: "E",
//Still can create isolate scope to not clobber parent scope variables.
scope: {},
template: "<p><span>Name: </span>{{ options.name }}{{ test }}</p>",
link: function (scope, element, attrs) {
scope.options = scope.$eval(attrs.options) || {};
if (attrs.name)
scope.options.name = attrs.name;
}
};
}]);
The directive requires a options parameter. In second case you have not supplied it and hence there is an error
If the isolated scope variable is optional use ? like
scope: {
options: "=?"
}
See my plunkr http://plnkr.co/edit/eGh6r1X7HzY1sZIDYZ69?p=preview
and documentation on isolated scope here http://docs.angularjs.org/api/ng/service/$compile

Angular JS - Is there a way to pass the directive's attribute to the template

on the Page
<rn-text-edit rn-scope="profile.first_name"></rn-text-edit>
on the js
app.directive("rnTextEdit", function () {
return {
restrict: 'E',
replace: true,
template:'<span>{{'+rn-scope+'}}</span>'
}
});
I know I can replace the DOM and access the attribute through link. I wonder if there is a way of passing the directive's attribute to a template.
If you are just displaying the value:
<rn-text-edit rn-scope="{{profile.first_name}}"></rn-text-edit>
-
app.directive("rnTextEdit", function () {
return {
restrict: 'E',
replace: true,
scope: {
rnScope: '#'
},
template: '<span>{{rnScope}}</span>'
}
});
If the directive needs to modify the value, you could use '=' and skip the double curlies.
fiddle
more info on scope and '#' in the Angular Directives page

Categories