Home > Article > Web Front-end > Analysis of the method of dynamically binding HTML in AngularJS
The example in this article describes the method of dynamically binding HTML in AngularJS. Share it with everyone for your reference, the details are as follows:
In Web front-end development, we often encounter the need to dynamically bind some HTML strings from the back end or dynamic splicing to the page DOM display, especially in content management System (CMS: the abbreviation of Content Management System), such needs are everywhere.
Readers of angular will definitely think of ngBindHtml first. Yes, angular provides us with this instruction to dynamically bind HTML. It will bind the calculated expression result to the DOM using innerHTML. However, the problem is not that simple. In Web security, XSS (Cross-site scripting, script injection attack) is a typical computer security vulnerability in Web applications. XSS attacks refer to injecting executable client-side code into web pages and successfully executing them by the browser to achieve the purpose of the attack, forming an effective XSS attack. Once the attack is successful, it may obtain some sensitive information of the user. Changing the user experience, inducing users and other illegal behaviors, sometimes XSS attacks are combined with other attack methods, such as SQL injection attacks on servers and databases, Click hijacking, relative link hijacking, etc. to implement phishing. The harm it brings is huge, and it is also a web The number one enemy of security. For more web security issues, please refer to the wiki https://en.wikipedia.org/wiki/Cross-site_scripting%E3%80%82
In angular, the default is not to trust the added HTML content. For the added HTML content , you must first use $sce.trustAsHtml to tell angular that this is trusted HTML content. Otherwise you will get $sce:unsafe exception error.
Error: [$sce:unsafe] Attempting to use an unsafe value in a safe context.
Here is a demo that binds a simple angular link:
HTML:
<div ng-controller="DemoCtrl as demo"> <div ng-bind-html="demo.html"></div> </div>
JavaScript:
angular.module("com.ngbook.demo", []) .controller("DemoCtrl", ["$sce", function($sce) { var vm = this; var html = '<p>hello <a href="https://angular.io/">angular</a></p>'; vm.html = $sce.trustAsHtml(html); return vm; }]);
For simple static HTML, this problem is solved. But for complex HTML, complexity here refers to HTML templates with angular expressions and instructions. For them, we not only hope to bind large DOM displays, but also hope to get angular's powerful two-way binding mechanism. ngBindHhtml will not be associated with $scope for two-way binding. If there are ngClick, ngHref, ngSHow, ngHide and other angular instructions in HTML, they will not be compiled. Clicking these buttons will not cause any reaction. The expression of binding The formula will not be updated. For example, if you try to change the last link to: ng-href="demo.link", the link will not be parsed, and the original HTML string will still be seen in the DOM.
To take effect, all instructions in angular need to go through compile. Compile contains pre-link and post-link, and is connected to specific behaviors before they can work. In most cases, compile will be automatically compiled when angular starts. But if it is a dynamically added template, you need to compile manually. Angular provides us with the $compile service to implement this function. The following is a more general compile example:
HTML:
<body ng-controller="DemoCtrl as demo"> <dy-compile html="{{demo.html}}"> </dy-compile> <button ng-click="demo.change();">change</button> </body>
JavaScript:
angular.module("com.ngbook.demo", []) .directive("dyCompile", ["$compile", function($compile) { return { replace: true, restrict: 'EA', link: function(scope, elm, iAttrs) { var DUMMY_SCOPE = { $destroy: angular.noop }, root = elm, childScope, destroyChildScope = function() { (childScope || DUMMY_SCOPE).$destroy(); }; iAttrs.$observe("html", function(html) { if (html) { destroyChildScope(); childScope = scope.$new(false); var content = $compile(html)(childScope); root.replaceWith(content); root = content; } scope.$on("$destroy", destroyChildScope); }); } }; }]) .controller("DemoCtrl", [function() { var vm = this; vm.html = '<h2>hello : <a ng-href="{{demo.link}}">angular</a></h2>'; vm.link = 'https://angular.io/'; var i = 0; vm.change = function() { vm.html = '<h3>change after : <a ng-href="{{demo.link}}">' + (++i) + '</a></h3>'; }; }]);
A directive called dy-compile is created here, which first listens to the html value of the bound attribute Change, when the html content exists, it will try to first create a subscope, and then use the $compile service to dynamically connect the incoming html and replace the current DOM node; the reason for creating the subscope here is to facilitate each When destroying the DOM for the first time, you can easily destroy the scope, remove the watchers function brought by HTML compile, and try to destroy the scope when the last parent scope is destroyed.
Because of the above compile compilation and connection, the ngHref instruction can take effect. Here is just an attempt to give an example of dynamic compile angular module. For specific implementation methods, please refer to your business to declare specific directives.
I hope this article will be helpful to everyone in AngularJS programming.
For more analysis on AngularJS’s method of dynamically binding HTML, please pay attention to the PHP Chinese website!