0

I have an Angular4 project that retrieves an string of HTML content from an API, the HTML can contain multiple blocks of <code>, and I want to highlight these blocks using PrismJS. To make this work, I need to call Prism.highlightAll() after the content has been rendered in the DOM, when I call Prism.highlightAll() after the API call, this doesn't do anything because the element is not instantaneously rendered, to get it to work I am doing a small wait before calling the renderer, this is not a good solution though, and wanted to know if there is a cleaner solution. This is what my code currently looks like:

this.dataService.getPageContent().subscribe(
      res => {
        this.html = this.sanitizer.bypassSecurityTrustHtml(res);
        setTimeout(function() { Prism.highlightAll(); }, 2000);
      },
      err => {
        alert('error');
      }
    ); 

1 Answer 1

1

You can do it with ngAfterViewChecked lifecycle hook. It will be called after your changes have been rendered. (It is called every time angular checks for changes also, hence the setHighlight guard to only do the highlighting once)

  1. Add new class field:

setHighlight = false
  1. Update your code:

this.dataService.getPageContent().subscribe(
  res => {
    this.html = this.sanitizer.bypassSecurityTrustHtml(res);
    this.setHighlight = true;
  },
  err => {
    alert('error');
  }
); 
  1. Add lifecycle hook:

ngAfterViewChecked() {
  if(this.setHighlight){
    Prism.highlightAll(); 
    this.setHighlight = false;
  }
}
Sign up to request clarification or add additional context in comments.

2 Comments

Thank you for your help, i ended up using the ngAfterViewChecked, but ditching the setHighlight guard, since ngAfterViewChecked is called after any change on any component (not just the current one), in my example on a page with alot of components, i had 10 calls to this function, and so a call from another component could arrive between the moment the guard is put to true and the moment rendering is made, and in this case the content will not be highlighted. If you can adjust your answer by specifying this (maybe as a remark), I'll mark your answer as acceptable.
It seems wasteful to call Prism function on each ngAfterViewChecked. I would either try: 1. Your original solution, but using setTimeout without specifying timeout milliseconds: setTimeout(()=>{ Prism.highlightAll(); }); 2. Keeping my solution. but wrapping this.setHighlight=true in setTimeout: setTimeout(()=>{this.setHighlight = true;});

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.