


Practical guide to dynamically updating Prism.js syntax highlighting code blocks in Angular
elements highlighted by Prism.js syntax in Angular applications when loading new code strings from the database. The core approach includes updating textarea content via FormControl and precisely re-highlighting specific code blocks with Prism.highlightElement() to ensure correct display and optimal performance of dynamic content.<h3 id="Understanding-the-question-Dynamic-content-and-the-challenge-of-Prism-js"> Understanding the question: Dynamic content and the challenge of Prism.js</h3>
<p> In modern front-end applications, dynamically loading content from the back-end and displaying it is a common requirement. When it comes to code presentation, syntax highlighting libraries such as Prism.js can greatly improve the user experience. However, updating dynamically loaded code strings to the textarea and <code> elements in the Angular component and ensuring Prism.js is re-highlighted correctly, you may encounter the following challenges:
- Update mechanism of textarea: In Angular responsive forms, the content of textarea is usually bound to FormControl through formControlName. Directly modifying a certain property of the component (such as currentCode) will not automatically update the value of FormControl, so the display content of the textarea will not change.
- Update of
elements:
The content of theelement is usually bound by Angular's interpolation ({{currentCode}}) or innerHTML attribute. Although modifying currentCode triggers Angular's change detection and updates the content of <code>, Prism.js does not listen to DOM changes by default and re-highlight automatically.
- Re-highlighting of Prism.js: The Prism.highlightAll() method scans the entire document for blocks of code that need to be highlighted, which is inefficient when handling dynamic local content updates and may cause performance issues.
To solve these problems, we need an accurate and efficient way to update the contents of textarea and and trigger Prism.js to re-highlight specific elements.
Core Solutions
The key to solving this problem lies in two points: one is to correctly update the FormControl associated with textarea; the other is to use the Prism.highlightElement() method to accurately re-highlight the target element after the content is updated.
1. Update textarea content: Use FormControl.setValue()
Since textarea is bound to the FormControl of a responsive form, we must update its value through that FormControl.
// Suppose you have a FormControl named 'content' this.form.get('content')?.setValue(newCodeString);
Use the setValue() method to ensure that textarea displays the latest code. To avoid accidentally triggering valueChanges subscriptions when updating FormControl (which may cause loop updates or other side effects), you can pass in emitEvent: false option when setValue():
this.form.get('content')?.setValue(newCodeString, { emitEvent: false });
2. Re-highlight code block: use Prism.highlightElement()
The Prism.highlightElement(element) method allows you to specify a specific HTMLElement for highlighting, rather than scanning the entire DOM. This is the most efficient way to dynamically load and update code blocks.
Sample code (implementation in PrismService):
In order to better encapsulate the functions of Prism.js, it is recommended to create a PrismService.
// prism.service.ts import { Injectable, ElementRef } from '@angular/core'; import * as Prism from 'prismjs'; // Make sure that prismjs and the corresponding language package @Injectable({ providedIn: 'root' }) export class PrismService { constructor() { } /** * Syntax highlighting of all qualified elements in the entire document* Note: For dynamic content updates, it is recommended to use highlightElement() */ highlightAll(): void { Prism.highlightAll(); } /** * Syntax highlighting of specified HTML elements* @param element HTMLElement that needs to be highlighted */ highlightElement(element: HTMLElement): void { if (element) { Prism.highlightElement(element); } } /** * Example: Convert HTML entities back to string (if needed) * @param htmlContent string containing HTML entity* @returns converted string*/ convertHtmlIntoString(htmlContent: string): string { const doc = new DOMParser().parseFromString(htmlContent, 'text/html'); return doc.documentElement.textContent || ''; } }
In the component, you will call this.prismService.highlightElement(this.codeContent.nativeElement); to highlight a specific element.
Integration in Angular components
Now we integrate the above solution into your Angular component. The core idea is to immediately update FormControl and trigger Prism.highlightElement() after the data is loaded and updated component properties.
First, make sure your component is able to reference textarea and elements.
// display-sourcecode.component.ts import { Component, OnInit, AfterViewChecked, ViewChild, ElementRef, Renderer2, OnDestroy } from '@angular/core'; import { FormBuilder, FormGroup } from '@angular/forms'; import { Subscription, fromEvent } from 'rxjs'; import { PrismService } from './prism.service'; // Assume that the PrismService path is correct @Component({ selector: 'app-display-sourcecode', templateUrl: './display-sourcecode.component.html', styleUrls: ['./display-sourcecode.component.css'] }) export class DisplaySourcecodeComponent implements OnInit, AfterViewChecked, OnDestroy { codeList: any[] = []; currentCode: string = ""; codeType: string = 'java'; // Default code type form: FormGroup; @ViewChild('textArea', { static: true }) textArea!: ElementRef<htmltextareaelement>; @ViewChild('codeContent', { static: true }) codeContent!: ElementRef<htmlelement>; // Make sure it is HTMLElement type private sub!: Subscription; constructor( private prismService: PrismService, private fb: FormBuilder, private renderer: Renderer2 ) { this.form = this.fb.group({ content: [''] }); } get contentControl() { return this.form.get('content'); } ngOnInit(): void { this.listenForm(); // Suppose you have the loadSourceCodes method to load the data // this.loadSourceCodes(); } ngAfterViewChecked(): void { // Remove or simplify the highlightAll() call here because we will call highlightElement() in a specific event // If there is no other requirement that requires global highlighting, you can delete this method or leave it blank} ngOnDestroy(): void { this.sub?.unsubscribe(); } /** * Called when new code is loaded from the database and needs to be displayed * @param item containing the code content, for example { code: "public class MyClass {}" } */ displaySourceCode(item: any): void { const newCode = item.code; // 1. Update the value of FormControl, which will update <textarea> // Use { emitEvent: false } to avoid triggering listenForm subscription, // Because we will manually update the <code> element below and highlight it. this.contentControl?.setValue(newCode, { emitEvent: false }); // 2. Update the content of the <code> element directly // Make sure to use Renderer2 to safely operate the DOM this.renderer.setProperty(this.codeContent.nativeElement, 'innerHTML', newCode); // 3. Trigger Prism.js to highlight specific <code> elements // Since DOM updates are asynchronous, in order to ensure that Prism.js is executed only after the content is updated, // You can use setTimeout(..., 0) or Promise.resolve().then() to put it into the microtask queue. // In most cases, direct calls can also work, but microtasks are more robust. setTimeout(() => { this.prismService.highlightElement(this.codeContent.nativeElement); }, 0); } /** * Listen to changes in form content, mainly used when users manually enter in textarea*/ private listenForm(): void { this.sub = this.form.valueChanges.subscribe((val) => { const modifiedContent = this.prismService.convertHtmlIntoString(val.content); this.renderer.setProperty(this.codeContent.nativeElement, 'innerHTML', modifiedContent); // When user inputs, the current <code> element is also highlighted directly. SetTimeout(() => { this.prismService.highlightElement(this.codeContent.nativeElement); }, 0); }); } // Original scroll synchronization logic, preserved here // @ViewChild('pre', { static: true }) pre!: ElementRef; // Assume that there is a <pre class="brush:php;toolbar:false"> element // private synchronizeScroll() { // const localSub = fromEvent(this.textArea.nativeElement, 'scroll').subscribe(() => { // const toTop = this.textArea.nativeElement.scrollTop; // const toLeft = this.textArea.nativeElement.scrollLeft; // this.renderer.setProperty(this.pre.nativeElement, 'scrollTop', toTop); // this.renderer.setProperty(this.pre.nativeElement, 'scrollLeft', toLeft 0.2); // }); // this.sub.add(localSub); // } }
Corresponding HTML template (display-sourcecode.component.html):
Summary of key modification points:
- displaySourceCode method:
- Use this.contentControl?.setValue(newCode, { emitEvent: false }); to update the value of textarea.
- Use this.renderer.setProperty(this.codeContent.nativeElement, 'innerHTML', newCode); to directly update the content of the
element.
- After the content is updated, call this.prismService.highlightElement(this.codeContent.nativeElement); to re-highlight. Use setTimeout(..., 0) to ensure that the DOM is updated before highlighting.
- listenForm method:
- The valueChanges subscription is fired when the user enters in the textarea.
- Similarly, after updating the innerHTML of
, directly call this.prismService.highlightElement(this.codeContent.nativeElement); for highlighting.
- ngAfterViewChecked method:
- If this method is only used to call prismService.highlightAll(), it can be removed or cleared because we have implemented more precise highlight control with highlightElement().
- HTML template:
- Remove the {{currentCode}} binding in the
element, because its contents will be set directly by component logic through renderer.setProperty or innerHTML.
- Remove the {{currentCode}} binding in the
Notes and best practices
- Performance optimization: Always use Prism.highlightElement() over Prism.highlightAll(), especially in dynamic content scenarios. highlightAll() will traverse the entire DOM, which is expensive.
- DOM Element Reference: Make sure ViewChild gets the
element correctly. If an element is in a conditional rendering such as ngIf, it may be necessary to check its existence in ngAfterViewInit or ngAfterViewChecked.
- Asynchronous data processing: When loading data from the API or database, make sure that after the data is successfully acquired and updated the component status, then perform methods such as displaySourceCode to update the UI and trigger highlighting.
- Error handling: Before calling prismService.highlightElement(), it is best to check if this.codeContent.nativeElement exists to avoid potential runtime errors.
The above is the detailed content of Practical guide to dynamically updating Prism.js syntax highlighting code blocks in Angular. For more information, please follow other related articles on the PHP Chinese website!

Hot AI Tools

Undress AI Tool
Undress images for free

Undresser.AI Undress
AI-powered app for creating realistic nude photos

AI Clothes Remover
Online AI tool for removing clothes from photos.

ArtGPT
AI image generator for creative art from text prompts.

Stock Market GPT
AI powered investment research for smarter decisions

Hot Article

Hot Tools

Notepad++7.3.1
Easy-to-use and free code editor

SublimeText3 Chinese version
Chinese version, very easy to use

Zend Studio 13.0.1
Powerful PHP integrated development environment

Dreamweaver CS6
Visual web development tools

SublimeText3 Mac version
God-level code editing software (SublimeText3)

This tutorial aims to solve the problem that the Vue.js project has blank pages by directly opening the index.html file without a web server or offline environment. We will dig into the reasons why the default Vue CLI build fails and provide a solution to package all Vue code and resources into a single HTML file, enabling the project to run independently on the local device without relying on any server environment.

Usemailto:inhreftocreateemaillinks.Startwithforbasiclinks,add?subject=and&body=forpre-filledcontent,andincludemultipleaddressesorcc=,bcc=foradvancedoptions.

UsethetitleattributeforsimpletooltipsorCSSforcustom-styledones.1.Addtitle="text"toanyelementfordefaulttooltips.2.Forstyledtooltips,wraptheelementinacontainer,use.tooltipand.tooltiptextclasseswithCSSpositioning,pseudo-elements,andvisibilityc

This tutorial details how to use CSS to accurately hide specific text content in HTML pages to avoid the problem of the entire parent element being hidden due to improper selectors. By adding exclusive CSS classes to the wrapping elements of the target text and using the display: none; attribute, developers can achieve refined control of page elements, ensuring that only the required parts are hidden, thereby optimizing page layout and user experience.

This article explores the challenge of capturing mousedown events on parent divs containing cross-domain iframes. The core problem is that browser security policies (same-origin policy) prevent direct DOM event listening on cross-domain iframe content. This type of event capture cannot be achieved unless the iframe source domain name is controlled and CORS is configured. The article will explain these security mechanisms in detail and their limitations on event interactions and provide possible alternatives.

This article details how to create a floating chatbot window triggered by clicking buttons using HTML, CSS, and JavaScript. Through fixed positioning and dynamic style switching, a floating button located in the lower right corner of the page is realized. After clicking, a chat window will pop up and a closing function is provided. The tutorial contains complete code examples and implementation steps designed to help developers easily integrate similar features into their website.

UseCSSfloatpropertytowraptextaroundanimage:floatleftfortextontheright,floatrightfortextontheleft,addmarginforspacing,andclearfloatstopreventlayoutissues.

Setthelangattributeinthehtmltagtospecifypagelanguage,e.g.,forEnglish;2.UseISOcodeslike"es"forSpanishor"fr"forFrench;3.Includeregionalvariantswithcountrycodeslike"en-US"or"zh-CN";4.Applylangtospecificelementswhe
