exposing an object in angularjs directive scope, can't access properties - angularjs

So, I have the following relatively simple Angularjs directive
app.directive('myDirective', function () {
return {
restrict: 'E',
scope: {
site: '#',
index: '#'
},
template: '<div>{{site}}</div>',
replace: true,
}
});
And here is where I call the directive in HTML
<div id="eventGraphic" class="span12">
<my-directive ng-repeat="site in IEvent.sites" site="{{site}}" index="{{$index}}"></my-directive>
</div>
Which, given that each site is an object, produces this output (copied from browser)
{"name":"Hurlburt","_id":"5148bb6b79353be406000005","enclaves":[]}
{"name":"Walker Center","_id":"5148cca5436905781a000005","enclaves":[]}
{"name":"test1","_id":"5148ce94436905781a000006","enclaves":[]}
{"name":"JDIF","_id":"5148cf37436905781a000007","enclaves":[]}
However, if I change the template in the directive to
template: '<div>{{site.name}}</div>',
it does not produce any output. This seems like a fairly straightforward use case, any ideas what I could be doing wrong? The desired output would be just the name field in each object.

You need to use '=' to map the object. '#' implies you're just passing a string value to the new scope.
app.directive('myDirective', function () {
return {
restrict: 'E',
scope: {
site: '=', //two-way binding
index: '#' //just passing an attribute as a string.
},
template: '<div>{{site}}</div>',
replace: true,
}
});
Then in your markup, don't use a binding in the attribute, just pass the expression:
<div id="eventGraphic" class="span12">
<!-- below, site="site" is passing the expression (site) to
the two way binding for your directive's scope,
whereas index="{{$index}}" is actually evaluating the expression
($index) and passing it as a string to the index attribute,
which is being put directly into the directive's scope as a string -->
<my-directive ng-repeat="site in IEvent.sites"
site="site"
index="{{$index}}"></my-directive>
</div>

Related

Angular js directive and restrict option

i was reading a write up on directive from this url https://docs.angularjs.org/guide/directive
The restrict option is typically set to:
'A' - only matches attribute name
'E' - only matches element name
'C' - only matches class name
'M' - only matches comment
<div ng-controller="Controller">
<my-customer></my-customer>
</div>
angular.module('docsRestrictDirective', [])
.controller('Controller', ['$scope', function($scope) {
$scope.customer = {
name: 'Naomi',
address: '1600 Amphitheatre'
};
}])
.directive('myCustomer', function() {
return {
restrict: 'E',
templateUrl: 'my-customer.html'
};
});
template html file
Name: {{customer.name}} Address: {{customer.address}}
please help me to understand what is the meaning of restrict: 'E', ?
i am looking for a example where restrict will be A or C
please show me the usage of restrict: 'A' and C
also tell me how could i pass multiple argument to directives ?
thanks
let say you have a directive 'myDirective'
if in restrict you have only C you can only use it as classes like this :
<div class="my-directive"></div>
If it's A it's as attribute :
<div my-directive></div>
If it's E it's as element
<my-directive></my-directive>
TO pass argument you generaly se attributes :
<div my-directive my-first-argument="toto" my-second-argument="titi"></div>
To get the value you have to way :
use the attr provided in link function
use the scope with one way or two way binding.
Personnaly i prefer the attribute approach when it comme to directive, element after and class in last. I have already bootstrap based on classes i don't want to clash with it.
please help me to understand what is the meaning of restrict: 'E', ?
The 'E' restriction will match by element name:
<my-customer></my-customer>
i am looking for a example where restrict will be A or C
please show me the usage of restrict: 'A' and C
The 'A' restriction will match by an element attribute:
<div my-customer=""></div>
The 'C' restriction will match by a class:
<div class="my-customer"></div>
also tell me how could i pass multiple argument to directives ?
It depends on your requirements, but one simple way is using an isolated scope:
.directive('myCustomer', function() {
return {
restrict: 'E',
scope: {
arg1: "#",
arg2: "#"
},
templateUrl: 'my-customer.html'
};
});
<my-customer arg1="first" arg2="second"></my-customer>
This SO answer gives a pretty good explanation of this process.
restrict is key to be used in DDO (Directive Definition Object) to inform what it Would be in view
for Example in DDO (Directive Definition Object)
Directive with restrict:E (Element)
Directive
app.directive('my-directive',function(){
return {
restrict: 'E', //means HTML Element
...
};
});
so directive in View for restrict:'E' as Element in HTML element as below
view
<myDirective></myDirective>
Directive with restrict:A (Attributes)
Directive
app.directive('my-directive',function(){
return {
restrict: 'A', //means HTML attribute
...
};
})
so directive in View for restrict:'A' as attribute in HTML element as below
view
<div myDirective></div>
Directive with restrict:'C' (class)
Directive
app.directive('my-directive',function(){
return {
restrict: 'C', //means HTML attribute
...
};
})
so directive in View for restrict:'C' as class in HTML element as below
view
<div class="myDirective"></div>
you can use Isolate scope (doesn't inherit from its parents scope) or you can pass variables to attributes which depends on your implementation both can used in directive's link and controller
for isolate scope DDO will be as
<my-directive variable1="hello" variable2="world" variable3="call()"></my-directive>
app.directive('myDirective',function(){
restrict:E,
scope:{
variable1:'#variable1',
variable2:'=varialbe2',
variable3:'&variable3'
}
})
Or you can also pass data through attributes and access them using attrs in Directive's link Function and $attrs DI in Directives Controller

Issue with dom manipulation inside Directive link function - Angularjs

I set up a directive as follows:
.directive('ogTakeATour', function() {
return {
restrict: 'E',
replace: true,
templateUrl: '../scripts/directives/TakeATourTemplate.html',
scope: {
content: '#',
uid: '#'
},
link: function(scope) {
angular.element(scope.uid).css("top","250px");
}
};
});
Directive template looks like this:
<div id="{{uid}}" class="tourContainer">
{{content}}
</div>
And this is how I call my directive:
<og-take-a-tour content="Content goes here" uid="menuTour"></og-take-a-tour>
However for some reasons this does not apply the css to the applicable div.
angular.element(scope.uid).css("top","250px");
Why is this? Could it be that the directive does not know what the id of my element is at the time the link function is running? How would I get around this if that is the case?
Angular's jQlite does not support search by id or CSS selector. So change your code like this:
angular.element(document.querySelector('#' + scope.uid)).css("top", "250px");

using ng-bind to define transcluded content on a directive that uses transclusion

Consider some-directive with the following definition object:
{
restrict: "E",
transclude: true,
template: "<div>content: <div ng-transclude></div></div>"
}
I can use it this way:
<some-directive>{{someContent}}</some-directive>
and not surprisingly, someContent will be placed where it has to.
But I want to be able to use it this way also:
<some-directive ng-bind='someContent'></some-directive>
Here is an example of the problem
It's not clear to me why you must use ng-bind over {{ }}, but if you must, then one way to solve this is to transclude the entire element using transclude: "element".
This, however, ignores the template property, so you'd need to manually add it in the compile function. And, you'd need to make the priority of your directive higher than that of ngBind (which has the default priority 1):
return{
restrict: "E",
transclude: "element",
priority: 10,
compile: function(tElem, tAttrs){
var template = "\
<div class='some-directive'>\
<div class='some-directive-header'>My custom component</div>\
<div class='some-directive-body' ng-transclude></div>\
</div>";
tElem.replaceWith(template);
}
};
Your forked plunker
This fixes your example:
<some-directive ><span ng-bind='someContent' /></some-directive>
http://plnkr.co/edit/qwKFYv1WAbpPTR1gGuqA?p=preview

AngularJS directive not properly receiving link passed in attribute

I've got an AngularJS directive that is not placing a string (intended to be a relative path to an image) inside one of the attributes in an HTML element and I'm at a loss as to why.
My item looks like the following:
item : {
name: 'Test Name',
link: 'Assets/logo.png'
}
If I step through the javascript, I'm correctly receiving the link from the webservice, so that's not the problem as my Angular controller properly shows the link in the $scope.
The following is what I have in the template for that controller that I'm having the problem with:
<my-directive name="{{item.name}}" link="{{item.link}}"></my-directive>
Here's the javascript for my directive:
angular.module('myModule').directive('myDirective', function() {
return {
restrict: 'E',
replace: true,
templateUrl: '/RelativePathToTemplateFile.html',
scope: {},
link: function($scope, element, attr, model) {
$scope.name = attr.name;
$scope.link = attr.link;
}
}
})
When I look at the rendered HTML, I have the following:
<div name="Test Name" link></div>
What's going on? How can I pass this link in properly?
Directive scope binding technique can resolve this issue. Try to use "#" to bind the directive property to the evaluated DOM attribute.
HTML
<div ng-controller="myCtrl">
<my-directive my-name="{{item.name}}" my-link="{{item.link}}"></my-directive>
</div>
Javascript
angular.module("myApp",[])
.controller("myCtrl",function($scope){
$scope.item = {
name:"Test Name",
link:"Assets/logo.png"
};
})
.directive("myDirective",function(){
return {
restrict: "E",
template: '<div name="{{myName}}" link="{{myLink}}">{{myName}}</div>',
replace: true,
scope:{
myName:"#",
myLink:"#"
}
};
});
Here is a jsFiddle DEMO, you could refer to it.
From the documentation:
function link(scope, element, attrs) { ... } where:
* scope is an Angular scope object.
* element is the jqLite-wrapped element that this directive matches.
* attrs is a hash object with key-value pairs of normalized attribute names and their corresponding attribute values.
so it's "attrs", not "attr"
try:
<myDirective name="item.name" link="item.link"></myDirective>
It will be better :)

Binding To Element Text In AngularJS

Is it possible to bind to the text of an element without actually dropping into the link function?
<blink>Text Here or {{ controllerText() }}</blink>
// add a namespace for custom directives
angular.module('mydirectives', []);
angular.module('mydirectives').directive('blink', function() {
return {
restrict: 'E',
template: '<marquee scrollamount="100%">{{ can i do it here? }} </marquee>',
scope: {
// can i do it here?
}
};
});
So this is done with transclusion which merges the content of the original element with the template. The ng-transclude tag in the template is required to get it to work.
<blink>Bring the blink back<blink>
// add a namespace for custom directives
angular.module('mydirectives', []);
angular.module('mydirectives').directive('blink', function() {
return {
restrict: 'E',
transclude: true,
template: '<marquee scrollamount="100%" ng-transclude></marquee>'
}
});
You absolute can.
scope: {
text: '='
}
This adds a text attribute to the isolate scope that is linked to the value of the text attribute from the element.
So you need to change the html slightly to:
<blink text="fromController"></blink>
And then add that fromController attribute in the enclosing controller.
Here's a (very annoying) fiddle.

Resources