Issue with dom manipulation inside Directive link function - Angularjs - 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");

Related

Angular directive rendering HTML mark up, how can I stop it?

I have an angular directive:
<some-dir text="{{characterDescription}}"></some-dir>
app.directive('someDir', function() {
"use strict";
return {
restrict: 'E',
transclude: false,
// replace: true,
template: '<p></p>',
scope: {
text: '#'
},
link: function(scope, elem) {
elem.append(scope.text);
}
};
});
The text which is passed into it looks like this:
{
characterDescription : <b>tall</b>
}
At the moment, it's rendering the HTML, so I'm seeing tall, but I want it to treat HTML as plain text, so I want to see <b>tall</b>.
Is there an angular way of accomplishing this in my directive?
elem.text(sometext)
This will not interpret the string as HTML, as you can see in the doc's.
jQuery.text() Docs
You could use
elem.text(scope.text);
Here's working fiddle: http://jsfiddle.net/1dL16fof/
And docs: http://api.jquery.com/text/#text2
EDIT beat to answer in comments.

I want to change the value of the template of directive

I define a directive like this:
module.directive("jump", function(html){
var text = html.getHtml();
return{
scope:{},
restrict:"AE",
template: text,
}
});
And I have a service to store the html, like this:
module.factory('html',function(){
var html = "";
return {
setHtml: function(text){
html = text;
},
getHtml: function(){
return html;
}
}
})
I want to change the template value when I enter article pageļ¼Œbecause the detail of every article are different, and I only can get it from API, it's like
<p><a href="#" ng-click="open(\'http://www.facebook.com\')"facebook</a></p>
I want to define a directive for every article to show the detail of article.
But now, when I enter one article page, the directive's template is defined, and if I want to see other article, the template value is the first article's detail.I want to know how to change it.
"Note: All services in Angular are singletons."
(src: https://docs.angularjs.org/guide/providers)
If you need to have the html be different for each instance of your directive, you can't use a singleton that restricts it to a single instance.
Why not just define the template from within the directive? It's a much cleaner pattern that way. Something like this:
directive in use:
<div ng-repeat="foo in dataFromApiThatYouGetFirst">
<jump url="{{foo.url}}" title="{{foo.title}}"></jump>
</div>
directive:
restrict: 'E',
template: '<p>{{vm.title}}</p>',
replace: true,
scope: {
url: '=?',
title: '=?'
},
controllerAs: 'vm',
bindToController: true,

When using two way binding in angular, when are the binded variables actually available?

I'm writing a directive that uses two-way binding.My directive looks like this:
bankSearch.directive('bankSearch',
function() {
return {
restrict: 'E',
scope: {
bankDetail: '='
},
templateUrl: "angular/views/self_signup/bank_search.html",
link: function(scope) {
//Now when link function runs, scope.bankDetail is undefined.
}
}
});
Html of template-url:
`<div class="row-fluid">
<input id="ifsc-code" class="span12" type="text" name="ifscCode"
ng-model="bankDetail.bankBranch.ifscCode"
should-be-ifsc
ng-keypress="onPressEnter($event, bankSearch.ifscCode.$valid)">
</div>`
This is how I'm using the directive:
`<bank-search
bank-detail="bankSearchModel.bankDetail">
</bank-search>`
I was under the impression that link function runs after linking(watchers setup) is done. If I'm correct then why am I getting undefined for scope.bankDetail inside my link function.
I'm new to Angular. Thanks for the help!
Might be bankSearchModel.bankDetail defines after directive is rendered. In case it is loaded from $http or something else. Try
link: function(scope) {
scope.$watch('bankDetail', function(val){
console.log(val);
});
}
And you'll see all changes of that variable.

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