Reputation: 6903
I have a pre
tag with dynamic text (unknown while the page is being loaded). This text may have ng commands. It will looks like this:
<pre>
Hello <span ng-click="test('args')">world</span> angular-JS!
</pre>
Because those dynamic tags are not exists while the page is being loaded, angularjs is not run them and the function test('args')
will never run.
So, I'm added a directive called compile-template
:
function compileTemplate($compile, $parse)
{
return {
link: function (scope, element, attr)
{
var parsed = $parse(attr.ngBindHtml);
function getStringValue() { return (parsed(scope) || '').toString(); }
//Recompile if the template changes
scope.$watch(getStringValue, function ()
{
$compile(element, null, -9999)(scope); //The -9999 makes it skip directives so that we do not recompile ourselves
});
}
}
}
And now my pre
tag is looks like this:
<pre compile-template>
Hello <span ng-click="test('args')">world</span> angular-JS!
</pre>
This is working good.
The problem starts when my text my text change for something like:
<pre compile-template>
Hello <span ng-click="test('args')">world</span> angular-JS! }}
</pre>
When I tried to compile this text ("Hello world angular-JS! }}") I getting this error:
Error: [$parse:lexerr] http://errors.angularjs.org/1.5.8/$parse/lexerr?p0=Unexpected%20next%20character%20&p1=s%200-0%20%5B%23%5D&p2=%23coordinates%3A21%7C37%7CN%7C87%7C04%7CW%7C%7C%7C%0A%0A%0A%7C%0A%7Cname%3D
at angular.js:38
at jc.throwError (angular.js:14179)
at jc.lex (angular.js:14101)
at s.ast (angular.js:14303)
at td.compile (angular.js:14771)
at kc.parse (angular.js:15700)
at g (angular.js:15865)
at k (angular.js:12364)
at ca (angular.js:9724)
at $b (angular.js:8743)
This because the "}}" string which is associated with broken JS code.
Example: https://jsfiddle.net/m69q87eg/
So, basicly what I tring to do is to allow <span>
s with JS, but nothing else.
I though to move the compile-template
directive to be part of my span. Like this:
<pre>
Hello <span compile-template ng-click="test('args')">world</span> angular-JS!
</pre>
But it's isn't working since the pre
outter HTML is treated like text.
What to do?
Upvotes: 4
Views: 513
Reputation: 4622
You can try using custom ngBindHtmlCompile
directive which will $compile
only the tags that were provided in the attributes (using querySelectorAll()
method or some other filtering logic of your choice):
var module = angular.module("demo", []);
module.directive('ngBindHtmlCompile', ['$compile', '$parse', function ($compile, $parse) {
return {
link: function (scope, element, attr) {
var parsed = $parse(attr.ngBindHtmlCompile);
function getStringValue() { return (parsed(scope) || '').toString(); }
scope.$watch(getStringValue, function (val) {
element.html(val);
if (!!attr.compileTags) {
$compile(element[0].querySelectorAll(attr.compileTags))(scope);
} else {
$compile(element, null, -9999)(scope);
}
});
}
}
}]);
module.controller('Demo', ['$scope', '$window', function Demo($scope, $window) {
var vm = this;
vm.template1 = `
populations of Eurasia <span>{{vm.untilStr}}</span> 1492, when Christopher Columbus first <span class=\"highlight-1\" ng-click=\"vm.test(2810)\">sailed into Caribbean waters on a quest to find a sea route to Asia. At that time the Western Hemisphere in general was unknown to Europeans. Following the discovery of the islands by Columbus, the area was quickly colonised by several Western cultures (initially Spain, then later</span>
In the Yucatan Channel. The same limit as that described for the Gulf of Mexico [A line joining Cape Catoche Light (21°37′N 87°04′W / 21.617°N 87.067°W / 21.617; -87.067{{#coordinates:21|37|N|87|04|W|||
|
|name=
}}) -- 1213123 <span class=\"highlight-1\" ng-click=\"vm.test(4117)\">and the extreme of Agujereada </span>`;
vm.test = function(args){ $window.alert(args); };
vm.untilStr = "until";
}]);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.min.js"></script>
<div ng-app="demo" ng-controller="Demo as vm">
<pre ng-bind-html-compile="vm.template1" compile-tags="span"></pre>
<br/>
</div>
Upvotes: 1