Troubles with Katex/ngx-markdown Display in Angular 16

In my Angular 16 application, I utilize the ngx-markdown library alongside Katex and other dependencies. A challenging situation arises when the backend (an LLM) responds with markdown text that conflicts with Katex delimiters during rendering.

I attempted to address this conflict by tweaking Katex's default delimiters as follows:

[
 {left: "$$", right: "$$", display: true},
 {left: '$', right: '$', display: false},
 {left: "\\(", right: "\\)", display: false},
 {left: "\(", right: "\)", display: false}, 
 {left: "\\begin{equation}", right: "\\end{equation}", display: true},
 {left: "\\begin{align}", right: "\\end{align}", display: true},
 {left: "\\begin{alignat}", right: "\\end{alignat}", display: true},
 {left: "\\begin{gather}", right: "\\end{gather}", display: true},
 {left: "\\begin{CD}", right: "\\end{CD}", display: true},
 {left: "\\[", right: "\\]", display: true},
 {left: "\[", right: "\]", display: true},
]

Despite adding some custom delimiters to improve rendering, issues persisted when the text contained characters like ( ) or [ ], causing conflicts in interpreting delimiters between Katex, Angular, and ngx-markdown, leading to incorrect rendering.

An illustration of the problematic rendering can be seen here: https://i.stack.imgur.com/1veLj.png

Below are snippets of the essential parts of the Angular script:

HTML -

<markdown lineNumbers katex [katexOptions]="optionsKatex" clipboard [clipboardButtonTemplate]="buttonTemplate">
 {{ mensagem.content }}
</markdown>

Angular TypeScript Component:

import { Component, OnInit, AfterViewInit } from '@angular/core';
import { KatexOptions } from 'ngx-markdown';

type questionAnswer={
  type: "Question" | "Answer",
  content: string,
  keyChat: number,
  likeSelected: boolean,
  dislikeSelected: boolean,
  isActive: boolean,
  isButtonsDisabled: boolean
}

export class TestComponent implements OnInit, AfterViewInit {

 public optionsKatex: KatexOptions = {
   delimiters: [
     {left: "$$", right: "$$", display: true},
     {left: '$', right: '$', display: false},
     {left: "\\(", right: "\\)", display: false},
     {left: "\(", right: "\)", display: false},
     {left: "\\begin{equation}", right: "\\end{equation}", display: true},
     {left: "\\begin{align}", right: "\\end{align}", display: true},
     {left: "\\begin{alignat}", right: "\\end{alignat}", display: true},
     {left: "\\begin{gather}", right: "\\end{gather}", display: true},
     {left: "\\begin{CD}", right: "\\end{CD}", display: true},
     {left: "\\[", right: "\\]", display: true},
     {left: "\[", right: "\]", display: true},
   ]
 };

 listMessagesQA: questionAnswer[] = [];

 ngOnInit(): void { }

 ngAfterViewInit(): void {
   // Sample data for demonstration purposes added to listMessagesQA array
 }

}

AppModule -

import { MarkdownModule, MarkedOptions } from 'ngx-markdown';

@NgModule({
  declarations: [
    AppComponent,
    TestComponent
  ],
  imports: [
    BrowserModule,
    MarkdownModule.forRoot({
      markedOptions: {
        provide: MarkedOptions,
        useValue: {
          gfm: true,
          breaks: true
        }
      }
    })
  ]
})
export class AppModule { }

Other relevant configurations and scripts have been included in the respective sections of the code snippet.

For a further understanding and additional references related to ngx-markdown setup, refer to the documentation links provided below:

  1. ngx-markdown Documentation
  2. Katex Autorender Documentation

Answer №1

Dealing with a similar problem. The string I'm working with has instances of \n - I opted to replace them with <br>

const str = input.replaceAll('\n', '<br>');

original

updated

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

One versatile service/module/library in Angular 1 that can be shared among several different "apps"

Trying to explain it as best I can: I currently have an angular app for one specific functionality. For example, I have a "campaigns" functionality that includes adding, editing, displaying all, and displaying in different ways. For the add and edit fun ...

Verifying AngularJS sub-forms based on conditions

Is it possible to use ng-required to check if an entire sub-form is required, rather than just individual fields? For instance, let's say I have three radio buttons and each one reveals a different sub-form. Only the sub-form corresponding to the sel ...

Arrangement of code: Utilizing a Node server and React project with a common set of

Query I am managing: a simple react client, and a node server that functions as both the client pages provider and an API for the client. These projects are tightly integrated, separate TypeScript ventures encompassed by a unified git repository. The se ...

Assign a true or false value to every attribute of an object

Imagine we have a scenario with an interface like this: interface User { Id: number; FirstName: string; Lastname: string; Age: number; Type: string; } and a specific method for copying properties based on a flag. ...

What methods are most effective when utilizing imports to bring in components?

Efficiency in Component Imports --Today, let's delve into the topic of efficiency when importing components. Let's compare 2 methods of importing components: Method 1: import { Accordion, Button, Modal } from 'react-bootstrap'; Meth ...

What sets apart calling an async function from within another async function? Are there any distinctions between the two methods?

Consider a scenario where I have a generic function designed to perform an upsert operation in a realmjs database: export const doAddLocalObject = async <T>( name: string, data: T ) => { // The client must provide the id if (!data._id) thr ...

Organize by a collection of strings or a collection of enums

Here is a list of objects that I have: enum MealType { Breakfast, Lunch, Dinner } interface FoodItem { name: string, type: MealType[], } const foodItems: FoodItem[] = [ { name: 'Pizza', type: [MealType.Lunch, MealType.Dinner ...

What is the role of the 'type' attribute in a button element

I am in need of a customized button that can optionally receive a type attribute: export interface ButtonProps { children: React.ReactNode; onClick?: (e: React.MouseEvent<HTMLElement>) => void; type: ?? } export const Button: React.Functio ...

Converting Enum into an array in TypeScript to return the keys of the Enum

After defining the following enum: export enum Types { Type1 = 1, Type2 = 2, ... } We can create an array based on this enum with the function below: export function EnumKeys<T>(obj: object): string[] { return Object.keys(obj) ...

When RxJS returns an empty observable, it does not trigger the successful action

I am working with a Rxjs effect that has the following structure: callApiPostSyncPushEffect$ = createEffect(() => { return this.actions$ .pipe( ofType(SyncActions.callApiPostSyncPushPullAction), mergeMap((action) ...

Pattern matching for validating multiple email addresses

I need assistance with validating multiple email inputs using regex in Angular. I am looking to enforce a specific format for the emails, such as: Examples: *****@zigurat.com *****@test.com *****@partlastic.com The ***** can be any characters, but the ...

When attempting to create a fresh NestJS module, a message pops up stating: "An error occurred while

Currently running MacOS Monterey with the M1 chip as my OS. I installed NestJS CLI using the command: sudo npm install -g @nestjs/cli When creating a new Nest project with nest new message, everything goes smoothly. However, when attempting to generate a ...

Handling Click and Mouse Events with React [react-sortable-hoc, material-ui, react-virtualized]

I have come across an interesting example that I would like to share with you. Check out this live working example on Stackblitz When the delete button on the red bin icon is pressed, the onClick event handler does not get triggered (sorting happens inst ...

Access route information external to the router outlet

Can we access the data parameters in a component that is located outside of a router outlet? const appRoutes: Routes = [ { path: '', component: SitesComponent }, { path: 'pollutants/newpollutant', component: PollutantComponent, data: { ...

The error message "TypeScript reflect-metadata Cannot find name 'Symbol'" indicates that TypeScript is unable to locate

While browsing through http://www.typescriptlang.org/docs/handbook/decorators.html#class-decorators, I encountered an issue where it could not find the Symbol. I was unsure whether this is related to the usage of reflect-metadata or if it was previously in ...

Writing TypeScript, Vue, and playing around with experimental decorators

After creating a Vue project through Vue-CLI v3.0.0-beta.15, the project runs smoothly when using npm run serve. However, TypeScript displays an error message stating that support for decorators is experimental and subject to change in a future release, bu ...

Utilizing Fullcalendar 5 in conjunction with Angular: Embedding Components within Events

Recently, my team made the transition from AngularJS to Angular 12. With this change, I upgraded Fullcalendar from version 3 to version 5 and started using the Angular implementation of Fullcalendar: https://fullcalendar.io/docs/angular While navigating t ...

Tips for accessing the return value from a method outside of its containing function

Having recently started using Angular, I'm encountering an issue with retrieving a return value from a function that I have implemented within another one. private validateKeyterm(): boolean { const val = this.form.value.term; if ...

What advantages does CfnAppSync provide over using AppSync in a CDK project?

We are in the process of enhancing our API by adding new JS resolvers and phasing out the VTL resolvers for an AWS AppSync CDK project, specifically built with Cfn<> Cloud Front CDK. The code snippet below illustrates how this can be achieved: ...

Creating a class and initializing it, then implementing it in other classes within an Angular application

Trying to grasp some angular fundamentals by creating a class structure. Unsure if this is the right approach. export class Cars{ Items:Car[]=[]; constructor() { this.Items = [ { id: "1", name: "Honda" ...