Using AngularJS Filters for HTML Parsing Last update: 2015-02-17
Let’s say you have some plain text in your AngularJS app which you want to display properly to the user. If you just assign your unfiltered text to a scope variable, you won’t have a good time. The user will see unformatted text with links he can not click, and other stuff which looks just plain and boring.
To fix this, I will show you how to easily write your own AngularJS Filter and parse the plain text to correctly formatted HTML text.
Looking at the wrong approach
First of all we take a look how everything would look without a filter. So for example you have this code in your app:
$scope.myHtmlText = "Take a look at my coding blog http://www.devdactic.com or send an email to saimon@devdactic.com";
The example is very simple, but the same thing could happen when you get a response from a Restful API like Twitter, Facebook or just your very own service. If you want to display the text in your app now with {{myHtmlText}}
, the result will look like this: Not what you expect from a website in the year 2015! The link is no link and the mail offers no option to quickly start the mailing tool of your choice. As you can see, this is really no option.
Creating your first AngularJS Filter
Now how can we solve this Problem? Angular Filters FTW! So in your apps folder, create a new file, load the script file inside your index.html and insert this to see how filters work:
.filter('parseUrl', function () {
return function (input) {
return 'parseUrl filter: ' + input;
};
});
As you can see, a filter is simply a function which will do stuff. To use the filter, open your HTML file where you previously had {{myHtmlText}}
and replace it with:
{{myHtmlText | parseUrl}}
This will use the filter on our variable and display the result. As we now know how AngularJS Filters work, let’s come back to our initial problem.
AngularJS Filter for parsing HTML
Before we create our killer Filter, we need to install another Angular dependency for displaying HTML correctly:
bower install angular-sanitize --save
<!-- To your index.html -->
<script src="bower_components/angular-sanitize/angular-sanitize.js"></script>
<!-- To your app.js -->
angular.module('filterInActionApp', ['ngSanitize'])
Angular sanitize will finally allow us to display HTML with tags as true HTML. Make sure to add the script to your index.html and the dependency to your angular.module()
.
“The input is sanitized by parsing the HTML into tokens. All safe tokens (from a whitelist) are then serialized back to properly escaped html string.”()
So now open up the filters file you created and replace the standard filter with this:
.filter('parseUrl', function($sce) {
var urls = /(b(https?|ftp)://[A-Z0-9+&@#/%?=~_|!:,.;-]*[-A-Z0-9+&@#/%=~_|])/gim;
var emails = /(w+@[a-zA-Z_]+?.[a-zA-Z]{2,6})/gim;
return function(text) {
if(text.match(urls)) {
text = text.replace(urls, '<a href="$1">$1</a>');
}
if(text.match(emails)) {
text = text.replace(emails, '<a href="mailto:$1">$1</a>');
}
return $sce.trustAsHtml(text);
};
});
Our HTML Filter currently has 2 Regular expressions which will look for URLs and email addresses. In our function we then check if the given text matches to one of our regex and if thats true, we replace the matching text with the correct HTML for a link or mail. Finally we return the string and call the Angular Strict Contextual Escaping to add some save escaping to our text.
This would now be a correct HTML string, however we need to display it in our view inside the Angular ngBindHtml directive so that our HTML string gets parsed and displayed correctly. To use this, your final code inside your view should look like this:
<p ng-bind-html="myHtmlText | parseUrl"></p>
And the result on your side will look like this:
Alternative implementation of your AngularJS Filter
Finally some words on how you could parse your text without adding the filter to your view. It’s possible to use Angular Filters inside your controller like this:
.controller('MainCtrl', function ($scope, parseUrlFilter) {
$scope.myHtmlText = parseUrlFilter('Your Text...');
});
This shows how to specify your generated filter as a dependency and afterwards using the function on the text you want to parse. The second alternative looks like this:
.controller('MainCtrl', function ($scope, $filter) {
$scope.myHtmlText = $filter('parseUrl')('Your text..');
});
This is a more generic way by injecting the $filter
dependency to your controller and then calling your specific filter function on it. However, just use what fits your needs the best!
Finally, if you want to start with some general AngularJS Filters, take a look at this collection of useful AngularJS Filter.
If this tutorial was helpful, follow me on twitter @schlimmson and leave a comment/ tweet it! Don’t forget to subscribe to my newsletter to receive new posts and infos via mail!
See a video version of this article below.
So long, Saimon