Leveraging PrismJS within an Angular application

I am currently implementing prismjs in my Angular app
Here's what I have so far

app.directive('nagPrism', [function() {
    return {
        restrict: 'A',
        transclude: true,
        scope: {
            source: '='
        },
        link: function(scope, element, attrs, controller, transclude) {
            if(!scope.source) {
                transclude(function(clone) {
                    element.html(clone);
                    Prism.highlightElement(element.find("code")[0]);
                });
            } else {
                scope.$watch(function() {return scope.source;}, function(v) {
                    if(v) {
                        Prism.highlightElement(element.find("code")[0]);
                    }
                });
            }

        },
        template: "<code ng-bind='source'></code>"
    };

}]);

This method works with code like this

<!-- This works  -->
<pre nag-prism source="code" class="language-css"></pre>

However, I would like it to be able to handle code structures like this as well

<pre nag-prism class="language-css">
<code>body {
color: red; 
}
  {{code}}

</code>
</pre>

To make things easier, I created a plunkr
Any suggestions?

Answer №1

From what I gather, you are aiming to create a directive that can highlight code provided as a constant, dynamically through variables, or a combination of both. If you are open to different syntax options, here is a potential solution.

The main issue lies in the fact that before applying Prism's highlight function, the code template must be compiled to replace {{variables}} with their corresponding values. In your current approach, the highlight function is being applied directly to the raw template.

The suggested approach involves changing the binding type from '=' to '@' and passing the source code as an attribute in all scenarios.

Previous binding:

scope: {
    source: '='
}

New binding:

scope: {
    source: '@'
}

Refer to Angular documentation for more information on bindings.

@ or @attr - bind a local scope property to the value of DOM attribute. The result is always a string since DOM attributes are strings. If no attribute name is specified, it is assumed to be the same as the local name. For example, with scope: { localName:'@myAttr' }, the widget scope property localName will reflect the interpolated value of hello {{name}}. As the name attribute changes, so will the localName property on the widget scope.

Here is an updated HTML sample (note that the old binding from the initial example has also been modified):

<!-- This works -->
<pre nag-prism source="{{code}}" class="language-css"></pre>

<!-- Now this works too! -->
<pre nag-prism source="body {
    color: red; 
}
{{code}}" class="language-css"></pre>

Complete revised directive code:

app.directive('nagPrism', [function() {
    return {
        restrict: 'A',
        scope: {
            source: '@'
        },
        link: function(scope, element, attrs) {
            scope.$watch('source', function(v) {
                if(v) {
                    Prism.highlightElement(element.find("code")[0]);
                }
            });
        },
        template: "<code ng-bind='source'></code>"
    };
}]);

You can view a working solution here: working sample

Edit: The directive has been updated to meet the target mentioned in the comment below.

To properly display transcluded content, manual compilation is required. This results in some adjustments to the directive code (the version below uses transcluded content if it is not empty and the source is not defined):

app.directive('nagPrism', ['$compile', function($compile) {
    return {
        restrict: 'A',
        transclude: true,
        scope: {
          source: '@'
        },
        link: function(scope, element, attrs, controller, transclude) {
            scope.$watch('source', function(v) {
              element.find("code").html(v);

              Prism.highlightElement(element.find("code")[0]);
            });

            transclude(function(clone) {
              if (clone.html() !== undefined) {
                element.find("code").html(clone.html());
                $compile(element.contents())(scope.$parent);
              }
            });
        },
        template: "<code></code>"
    };
}]);

This sample includes a code block bound to input to demonstrate that linking functions correctly: improved sample

Answer №2

Make sure to reload the Prism plugin once your controller has finished running.

app.controller('StartController', ['$scope', function($scope){

 console.log('hello');

 Prism.highlightAll(); // Just remember to do this!

}]);

Answer №3

Include this in the $stateChangeSuccess event handler

app.run(function($rootScope, $timeout){
$rootScope.$on('$stateChangeSuccess', function() {
  $timeout(function() {Prism.highlightAll()}, 0);
});

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

Guide to creating the onclick feature for a dynamic button in Meteor

<template name="actionTemplate"> {{#each action}} <button class="myButton" id={{_id}}>btn</button> {{> action}} {{/each}} </template> <template name="action"> <div class="sct" id={{_id}}> ...

Angular Grid Event Triggered by Checkbox Selection in the Header

I am currently utilizing ng-grid from AngularUI-Grid, where I have implemented a checkbox for row selection. Interestingly, it also provides a checkbox in the header. If a user selects the checkbox in the header, I need some event or method to trigger in ...

Utilizing JavaScript for enhancing the appearance of code within a pre element

Is there a way to dynamically highlight the code inside a pre element using vanilla JavaScript instead of JQuery? I'm looking for a solution that colors each tag-open and tag-close differently, displays tag values in another color, and attributes with ...

Navigating between child nodes in an HTML drop down list with multiple options and hierarchical structure

Hey there! I am looking to create a unique HTML hierarchy drop-down menu. It will have multiple levels or options, with each option having the potential for child nodes. When an option has child nodes, an arrow will appear next to it. Clicking on this ar ...

Changing the dynamic boundaries does not produce any results in the 'react-leaflet' library

Encountered an issue while trying to utilize the react-leaflet's bounds property. In my scenario, the application has predefined initial bounds in the state (referred to as fallback bounds) which are passed during the first component render. The archi ...

Conducting simultaneous tests on the mobile application and web browser to ensure optimal performance

Dear friends, I am in need of some assistance. I am looking to run end-to-end tests simultaneously on a mobile app and a web browser, make alterations on one platform, and check to see the changes reflected on the other multiple times. My current plan is t ...

JavaScript function to evaluate true conditions

I am encountering an issue while calling sub functions connected to if statements within my main function. Even though the sub functions are supposed to return true or false, the expected alerts are not appearing. if (functionAAA()){ alert("111 ...

Next.js is failing to detect the @lib folder

I am currently working on a Next JS project. Within my project, I have a specific directory structure: src Within this src directory, I have subdirectories such as pages, styles, lib Inside the lib directory, there is a file named config.js This file co ...

Is there a way to prevent pushing the same object into an array when adding objects to it?

While working on my project, I encountered an issue when creating a new array with objects checked in the checkboxes. Upon submitting, I received an error message: "flattenChildren(...): Encountered two children with the same key, .$3. Child keys must be u ...

Dynamic management of Spring Boot MongoDB Repositories across numerous databases

I was faced with the task of updating my Spring-Boot application to handle dynamically switching between multiple instances of the Mongo driver. The app already has Spring Boot MongoDB Repositories configured, but now we need to implement sass (dynamical ...

Iterating through each ID in a table/cell using .NET MVC with the @

Whenever the table is loaded, I need to run a JavaScript function on each row for cell 4. This function will format the JSON string that is inserted into it. The current code I have only updates the first row/cell... I believe the issue may be related to ...

Select the Best jQuery Package

Having a variety of packages available for selection. <div class="image-grid-item" data-search="select"> <input name="pack1" type="checkbox" style="display: none;"> </div> <div class="image-grid-item" data-search="select"> <inp ...

Using canvas elements to position divs in three.js

I am currently in the process of developing a custom animation player using Three.js for rendering objects, which is functioning perfectly. However, I am encountering difficulty when trying to incorporate control options at the bottom of the player (such a ...

When attempting to host a web application built using the Impact JavaScript game engine on a local server, Chrome throws CORS errors

Currently, I am working on a webapp created with the Impact JS game engine that needs to run locally without using a localhost (using file:///C:/...). The issue I am facing is with Chrome, as it is blocking the loading of images (mainly png/jpg) from the m ...

Eliminate any unauthorized characters from the email address

My goal is to assist users in avoiding entering invalid characters in an email input field (prior to server-side validation and cleanup). Please note: I am not validating emails on the frontend, only cleaning them up. // Coffeescript $(Element).find(&apo ...

What is the process of rotating a vector by 90 degrees to align it with a perpendicular plane, and then adjusting it further by 15 degrees out of

My ultimate objective is to determine a vector that represents the direction of the green line depicted in the image below, based solely on the positions of the yellow and green dots. To clarify, the angle of the vector can vary as long as its endpoint ...

Utilize the power of PIXI.js to effortlessly convert your canvas into a high-quality image without encountering

I'm currently working on exporting the entire canvas as a PNG using PIXI.js within a React app that incorporates react-pixi. My version is 6.5 and I've been trying out the following code: // MyComponent.tsx <button onClick={exportImage} /> ...

send multiple textbox values to controller in CodeIgniter

I am new to Codeigniter and I'm facing some difficulties in understanding how to accomplish a task. In my view page, there are five rows generated using a for loop. Each row consists of two select boxes and two input boxes. I don't know how to re ...

Error with YouTube API in Internet Explorer 8: Video not found

While using the iframe youtube api to handle video, everything runs smoothly on Chrome and Firefox. However, when trying to implement it on Internet Explorer 8, an error saying 'video' is undefined pops up. Any suggestions on how to resolve this ...

Modify the classname of two element class i

I am trying to change the class on click within an <i> element that has 2 classes. The first class is always "fa" and the second class can be either "fa-minus" or "fa-plus". I need to toggle between "minus" and "plus" based on the current class. Ca ...