AngularJS directive to parse and replace custom element contents
Solution 1
Here you go!
app.directive('markdown', function() {
return {
restrict: 'E',
transclude: true,
compile: function(elem) {
elem.replaceWith(Markdowner.transform(elem.html()));
}
}
});
Solution 2
ngTransclude is specifically designed for this.
myModule.directive('heading', function() {
return {
restrict: 'E',
replace: true,
transclude: true,
scope: true,
template: '<h1 ng-transclude></h1>'
};
}
Then use it like this:
<heading><span>{{foo}}</span></heading>
Here's a working fiddle (angular 1.2.7).
Also, I'm guessing you need some sort of markdown integration. Here's a version using transclude so that you end up with a div
container.
This one skips the whole transclude behavior and I'm guessing it's closer to what you're after.
Solution 3
You can get and set the compiled contents of the element in the link function using:
element.html() //get
element.html("blah") //set
Here is a sample based on Sergiu's sample below that processes the bindings contained within the html using scope.$eval()
, before calling the markdown converter:
http://jsfiddle.net/edeustace/4rE85/1/
angular.module('transclude', [])
.directive('markdown', function() {
var regex = /\{\{(.*?)\}\}/;
var converter = new Showdown.converter();
return {
restrict: 'E',
replace: true,
scope: true,
link: function (scope, element) {
var processTemplate = function(text){
var results = text.match(regex);
if(!results){
return text;
} else {
var value = scope.$eval(results[1]);
var replaceKey = new RegExp("{{" + results[1] + "}}","g");
text = text.replace(replaceKey, value);
return processTemplate(text);
}
};
var text = element.text();
var processed = processTemplate(text);
var markdownText = converter.makeHtml(processed);
element.html(markdownText);
}
};
});
which will work with:
<markdown>
# Bar {{foo}} {{foo}}
# {{bing}}
</markdown>
Or you can bind it to an attribute that you can then use in your directive:
app.directive('markdownWithBinding', function () {
var converter = new Showdown.converter();
return {
restrict: 'E',
scope: {
'md' : '@'
},
link: function ($scope, $element, $attrs) {
$scope.$watch('md', function(newMd){
var markdownText = converter.makeHtml(newMd);
element.html(markdownText);
});
}
}
});
Used like so:
<markdown-with-binding md="Hello {{name}}"></markdown-with-binding>
<!-- outputs Hello World!!! -->
Old Answer
This will happen in link() which is for linking the scope to the element. For structural changes where no scope is required you may be better off making your changes in the compile function:
app.directive('markdown', function () {
var link = function ($scope, $element, $attrs) {};
return {
restrict: 'E',
replace: true,
compile: function($element, $attrs, $transclude){
if($element.html() == "#Hello"){
$element.html("<h1>Hello</h1>");
}
return link;
},
}
});
Here's a great tutorial on components: http://www.youtube.com/watch?v=A6wq16Ow5Ec
Comments
-
Greg almost 2 years
I would like to create a simple markdown directive that accepts some content within the element, parses it and replaces it with html.
So this:
<markdown>#Heading</markdown>
or this (where $scope.heading = '#Heading';)
<markdown>{{heading}}</markdown>
Becomes this:
<h1>Heading</h1>
My directive so far (obviously not complete!):
.directive('markdown', function () { return { restrict: 'E', replace: true, link: function ($scope, $element, $attrs) { // Grab contents var contents = /* How do I do this? */ var newContents = Markdowner.transform(contents); // Replace <markdown> element with newContents /* How do I do this? */ } } })
I'm unsure of how to grab the contents of the directive? Would I need to compile it?!
Parsing Markdown is just an example
-
Greg over 10 yearsI've edited the question and added comments to the code. Would this handle
<markdown>{{heading}}</markdown>
? -
ed. over 10 yearsadded update about binding - binding to the markup contents as you have it here can't be done out of the box, but I'm sure is achievable.
-
ed. over 10 yearsI think Sergiu is on the right track (although the last sample doesn't work with bindings) - I've forked his last sample and added a function to process the bindings. jsfiddle.net/edeustace/4rE85/1
-
jessegavin over 10 yearsTurns out that this approach is deprecated in angular 1.2 though. ;(
-
Sergiu Paraschiv over 10 yearsGood thinking, it's a lot more useful with bindings.
-
Greg over 10 yearsWhat part is deprecated? Would this be an acceptable solution based on yours? plnkr.co/edit/44nAgaudUPCkd2Cw3hdp?p=preview
-
jessegavin over 10 yearsYep. Updating my answer. Thanks.