AngularJS: Compile a particular template

One pre tag on the page contains dynamic text that is unknown during page load. This text may include ng commands, as shown below:

<pre>
    Hello <span ng-click="test('args')">world</span> angular-JS!
</pre>

Since these dynamic tags do not exist when the page loads, AngularJS does not run them and the function test('args') will never execute.

To address this issue, I have implemented 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
            });
        }
    }
}

Now, my pre tag looks like this:

<pre compile-template>
    Hello <span ng-click="test('args')">world</span> angular-JS!
</pre>

This solution works well.

The problem arises when the text changes to something like this:

<pre compile-template>
    Hello <span ng-click="test('args')">world</span> angular-JS! }}
</pre>

When attempting to compile this text ("Hello world angular-JS! }}"), an error occurs:

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 error is due to the "}}" string being associated with broken JS code.

For example: https://jsfiddle.net/m69q87eg/

To solve this issue, I aim to allow only <span> elements with JS functionality, no other HTML content. My thought was to move the compile-template directive to be part of the span element, like so:

<pre>
    Hello <span compile-template ng-click="test('args')">world</span> angular-JS!
</pre>

However, this approach does not work as the outer pre HTML is treated as plain text.

How can I resolve this issue?

Answer №1

For a unique solution, consider implementing a custom ngBindHtmlCompile directive that will only compile the specified tags provided in the attributes. This can be achieved through filtering logic such as using the querySelectorAll() method:

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>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

The AngularJS factory does not hold on to its value

I have developed a basic factory to store a value from my authService: app.factory("subfactory", function() { var subValue = {}; return { set: set, get: get }; functi ...

Ways to retrieve lost methods in django-endless-pagination?

When new containers are added with ajax, the methods initialized for them stop working. How can I ensure that django-endless-pagination adds some JQuery to its generated containers? For instance: $(".fact").each(function() { $(this).css('border- ...

The DOM is failing to refresh in Vue.js even after the array has been updated

After receiving a list of items using AJAX, I store them in a data Array: loadSparepartFiles: function() { var vm = this; vm.activeSparepart.attachments = []; ajaxApi.loadJson('spareparts/sparepart/getFiles/'+vm.activeSparepartId, fu ...

The chosen option does not display any information

I am new to databinding an html control using ajax for the first time. After checking and debugging my ajax call, I can see that the data is retrieved successfully, but it does not show up in the select option. My javascript code is positioned at the botto ...

Update the DOM content once the scope variables have finished being translated

Looking to truncate table cells while fitting in as much content as possible. There's a great solution (fiddle) that I want to incorporate into a directive. Want to transform a table cell from <td>veryverylongunbreakablecontent</td> to ...

Tips for successfully passing a ViewBag in ng-click

<th><a href="javascript:;" ng-click="order(@ViewBag.desc)">Name</a></th> I am currently implementing this code and trying to fetch data from the view bag into my Angular Controller. However, I seem to be facing some challenges in a ...

Property '{}' is not defined in type - Angular version 9.1.1

Currently, I am working with Angular CLI version 9.1.1 and I am attempting to update certain data without updating all of it. form: UserInfo = {adresse : {}}; UserInfo.interface export interface UserInfo { id_user: string; username: string; em ...

Ways to retrieve an array following a function call

After a lot of testing and troubleshooting, I finally got my array to function properly in the console. However, when I click the button, the array is displayed on the console but not in my HTML. TS: jogar(){ for(var u=0;u<6;u++){ this.y ...

What is the method for individually extracting values from HTML using class li?

Is there a way to extract each value from the HTML within the li class separately? I have tried various methods but none have been successful. Can anyone provide a solution? Here is my JavaScript code: $(document).ready(function() { $(".list-grou ...

Utilizing Angular Directives and Controllers for Improved Efficiency

I have developed a custom dropdown option selector which is functioning well. It includes functions to fetch data from a specified URL in order to populate a list. However, the issue arises when I attempt to reuse this component in a different section of ...

Save log discrepancies to a document

Upon completing my website for graduation, there is still one important feature I want to add. I would like to implement a script that sends the name of the website where it is installed, as well as any error messages, to my website. For instance: The fol ...

Avoid Conversion of HTML Entities in Table Cells

<table> <tr> <td>&gt;</td> </tr> <tr> <td>&&#xfeff;GT</td> </tr> </table> In the code snippet above, I have table cells containing HTML entities. A re ...

Why do two date type variables have identical content?

I'm trying to grasp why the value of d1 changes in each alert(). Any insights would be greatly appreciated. Thanks! <script> d1 = new Date("01/01/2015"); d2 = d1; alert(d1); d2.setDate(d2.getDate()+10); alert(d1); </script> ...

Ways to halt a message callback?

Looking at some lines of code from a canvas sprite animation on GitHub, I am curious about how to stop the animations once the sprite has finished. window.requestAnimFrame = (function(callback) { // Function for handling animation frames return window.r ...

How can I include inline CSS directly within a string instead of using an object?

Is there a way to write inline CSS in a string format instead of an object format? I attempted the following, but it did not work as expected: <div style={"color:red;font-weight:bold"}> Hello there </div> What is my reason for want ...

Retrieve a CSV file from the server using Angular and JavaScript

How can a visitor download a CSV file from the server using Angular 7? Many websites suggest creating a CSV file dynamically from data and then using blob creation for downloading. However, I already have the CSV file on the server and want to directly do ...

Modifying the variable value upon clicking

I need to update a variable value on click, in order to send the updated value via ajax and load data either in ascending or descending format. Below is the JavaScript section at top of the page. var sortDirection = '0'; Now, here is the corre ...

Display a loading progress bar with jQuery AJAX as your single page website content loads

I am currently working on a simple web page layout that consists of a navigation bar at the top and a body wrapper. Whenever a user clicks on a link in the navigation bar, I use .load to load the content of the page into the wrapper div. $(this).ajaxStar ...

Guide to acquiring the webViewLink using Google Drive Api v3?

I'm having trouble locating the webViewLink. The documentation (https://developers.google.com/drive/api/v3/reference/files) states that I should receive this parameter when requesting gapi.client.drive.files.list(). However, I don't even have a c ...

How can I make the columns in Next.js / Tailwind expand horizontally first instead of vertically?

Recently, I decided to customize the Next.js Image Gallery starter for some hands-on experience in full stack development with Next.js. My goal was to create a chronological photo gallery of a recent trip, but encountered an issue where the responsive colu ...