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

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.

Related

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 Skobbler in AngularJS directive: 'Map container is already initialized.'

Using a directive to render the Skobbler leaflet:
angular.module('app.directives').directive('skm', function()
{
return {
restrict: 'E',
replace: true,
scope: false,
template: '<div></div>',
link: function(scope, element, attrs) {
var map = L.skobbler.map('skm', scope.skm);
// ....
}
}
});
This directive is used on different routes/partials in a similar way:
<skm id="skm"></skm>
Version info:
Skobbler 2.0
AngularJS 1.2.16
When moving from page 1 to page 2, no problem. However, going back to page 1:
Error: Map container is already initialized.
I've tried storing the map object and using map.remove(), which removes the error but stops the map from rendering.
FIXED: See my answer below. (Use unique ID's in each partial and grab those)
Fixed: Simply put a unique ID in each partial and grab the ID in the directive, then create the leaflet with this ID.
Partial 1:
<skm id="skm1"></skm>
Partial 2:
<skm id="skm2"></skm>
Directive:
angular.module('app.directives').directive('skm', function()
{
return {
restrict: 'E',
replace: true,
scope: false,
template: '<div></div>',
link: function(scope, element, attrs) {
var map = L.skobbler.map(attrs.id, scope.skm);
// ....
}
}
});
What didn't work:
replacing the outerHTML with original HTML on directive $destroy (directive didn't play well)
map.remove() (Skobbler didn't care)
Shouting profanities at the Skobbler library (Skobbler didn't care)
Skobblerjs is a "thin" fork of leafletjs so (most likely) the error comes from the leaflet logic and not the skobbler logic.
There are some other mentions of this error, see of any of following are of help to you:
https://groups.google.com/forum/#!topic/leaflet-js/xDNcNBAZq8o
http://forums.enyojs.com/discussion/540/leaflet-maps
If not - then include a jsfiddle or plunker example so that we're able to debug

Utility functions for directives

Say I want to make an angular directive that generates links to resources that look like this:
link/to/resource/1234
from an object that looks like:
resource = {
id: 1234,
otherProperty: 'foo'
}
How can I do this effectively w/ a directive? Ie, I'd like to not have to repeat the part that goes '/link/to/resource/{{id}}'. I can't seem to get that to work right. One of the several things I've tried:
app.directive('myResource', function() {
return {
restrict: 'E',
scope: {
resource: '='
},
baseUrl: 'link/to/{{resource.id}}',
template: '{{baseUrl}}'
};
});
which ends up rendering:
Other things I've tried (like making baseUrl a function/sticking it in scope) have resulted in similar things/errors.
Is there a way to get something like this to work?
One way to handle this is to use the directive's link function to set the variable up for you, like this:
link: function(scope) {
scope.baseUrl= 'link/to/'+scope.resource.id;
},
template: '{{baseUrl}}'
Here's a working fiddle
Alternatively you could use this approach:
link: function(scope) {
scope.baseUrl= 'link/to/';
},
template: '{{baseUrl}}{{resource.id}}
Here's the fiddle
just write a directive controller
app.directive('myResource', function() {
return {
restrict: 'E',
scope: {
resource: '='
},
controller: function($scope){
$scope.getBaseUrl = function(resource){
return 'link/to/'+resource.Id;
};
},
template: '<a ng-href="http://{{getBaseUrl(resource)}}">{{getBaseUrl(resource)}}</a>'
};
});
a function makes more sense,because you wont have manage resource state change.You may answer that the Id is unlikely to change but in my opinion,it's better practice in general.
http://plnkr.co/edit/I2QKNB1o8jvZf7kCDT2v?p=preview

Angular: How to get content from a custom div

I want to get a the content from a custom div tag, I tried various ways to do it, not working well. Here is an example. The general item is to retrieve the content in the custom directive tags. and then bind them into the template. I hope some one can give me a suggestion or solution that does it, or does similar things
The html
<questions>
<qTitle> this is title</q-title>
<qContent> this is content <q-content>
</questions>
The angular js
var app = angular.module('app'[]);
app.directive('questions', function () {
return {
transclude: true;
template: "<div class='someCSSForTitle'>{{qTitle}}</div>"+
"<div class='someCSSForContent'>{{qContent}}</div>"
link:(scope, element, attrs)
scope.qTitle = element.find(qTitle).innerHTML
scope.qContent = element.find(qContent).innerHTML
}
}
});
First I'd advise you to read the AngularJS Guide. You didn't even copy-paste the structure correctly and you have javascript and even html errors.
Basic fixes:
HTML
<questions>
<q-title>this is title</q-title>
<q-content>this is content</q-content>
</questions>
Why do you mix qTitle and q-title?
As regarding JS:
app.directive('questions', function () {
return {
restrict: 'E',
replace: true,
template: "<div class='question'>{{title}}</div>", /* simplified */
link: function(scope, element, attrs) {
scope.title = "hallo";
console.log(element.html());
}
};
});
by default, restrict is set to 'A'. That means attributes. Your syntax is for elements.
replace set to true is not compulsory. However, because the browser doesn't understand your elements but does understand the content ("this is title"), it will print it.
the link function has to be a function. you had syntax errors there (same for transclude: you had something that you were not using followed by ";")
You can print the element to know the contents. If you do, you'll see that element in link is not question.
Now if you want to read the content, you can use a transclude function or create directives for each part and create the template separately. This seems simpler. Live example:
app.directive('questions', function () {
return {
restrict: 'E',
transclude: true,
replace: true,
template: "<div class='question' ng-transclude></div>",
};
});
app.directive('qTitle', function () {
return {
restrict: 'E',
transclude: true,
replace: true,
template: "<div class='title' ng-transclude></div>",
};
});
In this case you translude the contents to an inner div.
You can also define custom complex transclude functions in the compile phase but this doesn't seem necessary here.

Dynamic template in directive based on attributes?

Ive seen a bunch of questions pretty similar to this, but I'm new to Angular so they aren't quite making sense. Here's my sitaution:
I have a directive defined:
robus.directive("titlebar", function() {
return {
restrict: "E",
scope: { title: '#title' },
template: "<header class='bar-title'><h1 class='title'>{{title}}</h1></header>",
replace: true
}
});
I use this directive like this:
<titlebar title="{{workout.name}}"></titlebar>
Ideally, I want to add optional attributes into this, like:
<titlebar title="{{workout.name}}" editButton="true" closeButton="true"></titlebar>
How do I handle these in the template definition? I've been reading about a $compile() function that I need to override, but haven't been clear on how to do so. The templates are just simple strings, so I feel like I can just do them inline versus referencing them as separate files.
Thanks!
Make them accessible within the directive by adding them to the scope statement, just as you have the title. Then add the buttons to the template, and conditionalize them like so:
robus.directive("titlebar", function() {
return {
restrict: "E",
scope: { title: '#title', edit: '#editButton', cancel: '#cancelButton' },
template: "<header class='bar-title'><h1 class='title'>{{title}}</h1><span ng-show='edit'>Edit</span><span ng-show='cancel'>Cancel</span></header>",
replace: true
}
});
<titlebar title="{{workout.name}}" edit-button="true" cancel-button="false"></titlebar>
Note that it's editButton in the directive and edit-button in the HTML; there's a built-in conversion from hyphenated to camel-case that will bite you if you're not aware of it.
Also, I recommend the use of transclude here, as I think it will read a bit more cleanly:
robus.directive("titlebar", function() {
return {
restrict: "E",
scope: { edit: '#editButton', cancel: '#cancelButton' },
template: "<header class='bar-title'><h1 class='title' ng-transclude></h1><span ng-show='edit'>Edit</span><span ng-show='cancel'>Cancel</span></header>",
transclude: true,
replace: true
}
});
<titlebar edit-button="true" cancel-button="false">{{workout.name}}</titlebar>

Resources