javascripthtmlcssangularionic-framework

Dynamically add color in ion-card text based on regex


I want to add a span around some text when a # or a @ is detected so I can change the color to make it look like usernames and hashtags in twitter. My code looks like this:

TS FILE:

ngOnInit(): void {
    this.glyphService.getAllGlyphs().subscribe(
      result => {
        this.items = result;
        // sort by rune id so list is newest to oldest
        this.items.sort((a, b) => Number(b.rune) - Number(a.rune));
        for (let i = 0; i < this.items.length; i++) {
          this.items[i].glyph_content = this.replaceIt(this.items[i].glyph_content);
          console.log(this.items[i])
        }
        console.log(this.items)
      }
    );
  }

  replaceIt = (str: string) => {
    const regex = /\B([\#\@][a-zA-Z]+\b)(?!;)/g;
    const subst = `<span style="color:blue">$1</span>`;
    const result = str.replace(regex, subst);
    return result;
 }

HTML FILE:

  <ion-card *ngFor="let item of items" >
    <ion-card-header>
      <ion-card-title>&#64;{{item.username}}</ion-card-title>
      <ion-card-subtitle>{{item.glyph_date}}</ion-card-subtitle>
    </ion-card-header>
    <ion-card-content>
      {{item.glyph_content}}
    </ion-card-content>
 </ion-card>

I’m successfully replacing the text like I want to, however it’s just winding up as text instead actual tags and looks like this: test <span style="color:blue">@hey</span> <span style="color:blue">@uh</span> wow <span style="color:blue">#ah</span> words <span style="color:blue">#oh</span> Is there a way for me to change my code so I’m actually dynamically wrapping the target text in real spans like I want? Is it possible to use *ngIf in some creative way here?


Solution

  • We need to use DomSanitizer and [innerHtml] for this to work.

    In your component.ts file:

    // TS File
    import { DomSanitizer, SafeHtml } from '@angular/platform-browser';
    
    export class YourComponent implements OnInit {
      items: any[] = [];
    
      constructor(
        private glyphService: GlyphService,
        private sanitizer: DomSanitizer
      ) {}
    
      ngOnInit(): void {
        this.glyphService.getAllGlyphs().subscribe(
          result => {
            this.items = result;
            // sort by rune id so list is newest to oldest
            this.items.sort((a, b) => Number(b.rune) - Number(a.rune));
            for (let i = 0; i < this.items.length; i++) {
              this.items[i].glyph_content_html = this.sanitizer.bypassSecurityTrustHtml(
                this.replaceIt(this.items[i].glyph_content)
              );
            }
            console.log(this.items);
          }
        );
      }
    
      replaceIt = (str: string): string => {
        const regex = /\B([\#\@][a-zA-Z]+\b)(?!;)/g;
        const subst = `<span style="color:blue">$1</span>`;
        const result = str.replace(regex, subst);
        return result;
      }
    }
    

    In your HTML:

    <ion-card *ngFor="let item of items">
      <ion-card-header>
        <ion-card-title>&#64;{{item.username}}</ion-card-title>
        <ion-card-subtitle>{{item.glyph_date}}</ion-card-subtitle>
      </ion-card-header>
      <ion-card-content [innerHTML]="item.glyph_content_html">
      </ion-card-content>
    </ion-card>