I am trying to make a directive for HTML using AngularJS so that I can render Markdown in the browser. What I want is to have a <markdown>
tag with a src
attribute that will load the file specified and render it correctly.
I have partially implemented this as follows -
function Main($scope) {
$scope.theContent = '#asgakfgajgfas\n##akfaljfqpo\ndhvkajvlbndvm';
};
angular.module('myApp', [])
.directive("markdown", function ($compile) {
return {
restrict: 'E',
require: 'model',
scope: {
value: "=model"
},
template: '<div ng-bind-html-unsafe="value | markdown"></div>'
};
}).filter('markdown', function () {
var converter = new Showdown.converter();
return function (value) {
return converter.makeHtml(value || '');
};
});
And the corresponding HTML -
<div ng-controller="Main">
<markdown model="theContent"></markdown>
</div>
Here is the jsFiddle link(based on John Linquist's example) for the above code. This does not work with the src
attribute, however it is able to load a markdown text string specified in a model.
Could you tell me how I can change this code to load the file specified in the src
tag. I was thinking of using the $http
provided by AngularJS but couldn't get my head around actually using it inside the directive definition.
What I would like to achieve is <markdown src="a/b/c.md" />
I have finally come up with a solution to this.
// Render markdown in the HTML page
app.directive("markdown", function ($compile, $http) {
var converter = new Showdown.converter();
return {
restrict: 'E',
replace: true,
link: function (scope, element, attrs) {
if ("src" in attrs) {
$http.get(attrs.src).then(function(data) {
element.html(converter.makeHtml(data.data));
});
} else {
element.html(converter.makeHtml(element.text()));
}
}
};
});
I define a custom link
function which either takes the content of the <markdown>
tags and renders them correctly, or it gets the content of the file given in the src
attribute and renders that.
Another alternative, based on the answer above. This one uses angular eval, watch and sanitize, which means that it is useful for live editing, sanitizes the html, which is necessary as markdown leaves inline html such as a script tag as-is, and uses an angular expression to access the data.
$scope.data = {markdown:"#H1"}
<div markdown="data.markdown">
</div>
<textarea ng-model="data.markdown"></textarea>
angular.module('markdown',['ngSanitize']).directive('markdown', function ($sanitize) {
var converter = new Showdown.converter();
return {
restrict: 'A',
link: function (scope, element, attrs) {
function renderMarkdown() {
var htmlText = converter.makeHtml(scope.$eval(attrs.markdown) || '');
element.html($sanitize(htmlText));
}
scope.$watch(attrs.markdown, function(){
renderMarkdown();
});
renderMarkdown();
}
}
});
Here is the simplest generic solution I could muster as using $sanatize or $sce is not required:
http://plnkr.co/edit/6OK0RcMChmD1S3JtfItp?p=preview
<body ng-app="myApp">
<textarea ng-model="test"></textarea>
<div markdown="test"></div>
<script src="//code.angularjs.org/1.3.0/angular.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/showdown/0.3.1/showdown.min.js"></script>
<script>
angular.module('myApp', [])
.run(function($rootScope) {
$rootScope.test = '#foo\r- bar\r- baz'
})
.directive('markdown', function () {
var converter = new Showdown.converter();
return {
restrict: 'A',
link: function (scope, element, attrs) {
function renderMarkdown() {
var htmlText = converter.makeHtml(scope.$eval(attrs.markdown) || '');
element.html(htmlText);
}
scope.$watch(attrs.markdown, renderMarkdown);
renderMarkdown();
}
};
});
</script>
</body>
RESULT:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With