2016-11-19 3 views
2

Ich versuche, Highlight JS in meiner Angular 2-App zu verwenden, und habe Probleme, herauszufinden, wie ich es verwenden kann, wenn der Codeblock keine statische Information ist. Was ich meine, ist, dass die Code-Zeichenfolge vom Server über einen http get-Aufruf kommt.Verwenden von Highlight JS in Angular 2

Also, wenn ich diese:

export class WorkstationComponent implements OnInit { 

    private submission = new Submission(); 
    private criteria = new Array<ExerciseCriteria>(); 
    private codeString:string = ` 
     /* HelloWorld.java 
     */ 

     public class HelloWorld 
     { 
      public static void main(String[] args) { 
       System.out.println("Hello World!"); 
      } 
     }`; 

    constructor(private _router:Router, private submissionService:SubmissionService, 
       private activatedRoute:ActivatedRoute){} 

    @ViewChild('code') codeElement: ElementRef; 

ngOnInit(){ 
    this.activatedRoute.params 
     // (+) converts string 'id' to a number 
     .switchMap((params: Params) => this.submissionService.getSubmission(+params['id'])) 
     .subscribe(data => this.success(data), 
        error => this.fail(error)); 

} 

success(data:any){ 
    this.submission = data; 
    this.criteria = data.criteria; 
    hljs.highlightBlock(this.codeElement.nativeElement); 
} 

Es gibt kein Problem ...

success

Wenn ich jedoch auf

success(data:any){ 
    this.submission = data; 
    this.criteria = data.criteria; 
    this.codeString = data.code; 
    hljs.highlightBlock(this.codeElement.nativeElement); 
} 

ändern bekomme ich diese :

fail

Was mache ich falsch? Die HTML ist die gleiche

   <pre> 
        <code #code highlight class="java"> 
         {{codeString}} 
        </code> 
       </pre> 
+2

Meine Vermutung 'highlightBlock' ist immer Feuer vor' codeString' Bindung wird ausgewertet. Möglicherweise müssen Sie auf den nächsten Haken warten und die Funktion "highlightBlock" aufrufen. Wie bei 'setTimeout (() => {hljs.highlightBlock (this.codeElement.nativeElement);}, 0);' anstelle von 'hljs.highlightBlock (this.codeElement.nativeElement);' –

Antwort

2

Es geschieht, weil highlightBlock Funktion Feuer vor dem inneren code Elementinhalt isn wird immer nicht verfügbar. Eine der zu lösenden Lösungen ist setTimeout, um highlightBlock einen Tick später anzuwenden, sobald alle Bindungen angewendet werden. Aber unnötigerweise wird dies eine weitere Änderungserkennung ausführen.

Besser als zu warten, dass innerer Inhalt auf DOM beschränkt ist, konnten Sie es manuell auf textContent von DOM anwenden und dann highlightBlock Funktion anwenden.

-Code

success(data:any){ 
    this.submission = data; 
    this.criteria = data.criteria; 
    this.codeString = data.code; 
    //making sure code is populated by below line 
    this.codeElement.nativeElement.textContent = data.code; 
    hljs.highlightBlock(this.codeElement.nativeElement); 
} 
+0

Der setTimeout-Ansatz funktionierte für mich . Fehler erhalten "this.codeElement.nativeElement.textContent ist keine Funktion "mit dem zweiten Ansatz. –

+1

@ManuelZamith Ahh .. textContent ist Eigenschaft keine Methode (Ich hatte versehentlich Methode dort :() .. überprüfen aktualisierte Antwort, sollte es funktionieren :) –

+0

Brilliant :). Vielen Dank so viel. –

-1

Wie in @PankajParkar Kommentar erwähnt, wird highlightBlock Feuer bekommen, bevor codeString Bindung ausgewertet wird.

Das Verschieben dieser Funktion auf den nächsten Tick (unter Verwendung von setTimeout) funktioniert, da Angular die Änderungserkennung und DOM-Aktualisierung durchführen kann.

Die alternative Lösung ist die Verwendung von Pipe. Hier ist Pipe, die ich für die Code-Hervorhebung unter Verwendung Prism.js verwende. Sie können es leicht aktualisieren Highlight.js zu verwenden:

@Pipe({ name: 'prism' }) 
export class PrismPipe implements PipeTransform { 
    constructor(private sanitizer: DomSanitizer) {} 
    transform(value, args) { 
    if (!isString(value)) { 
     throw new InvalidPipeArgumentException(PrismPipe, value); 
    } 
    let lang = args[0].toString().trim().toLowerCase(); 

    let grammar = Prism.languages[lang]; 
    // fallback to clike 
    if (!grammar) grammar = Prism.languages.clike; 
    return this.sanitizer.bypassSecurityTrustHtml(Prism.highlight(value, grammar)); 
    } 
} 

Dann benutze ich es im Code wie folgt aus:

<pre [innerHtml]="codeString.source | prism:codeString.lang"></pre> 
0

In Angular4, highlight.js von der Komponente zu verwenden:

import {Component, ViewEncapsulation} from '@angular/core'; 
 
import * as hljs from 'highlight.js'; 
 

 
@Component({ 
 
    selector: 'cus-com', 
 
    template: ` 
 
    <pre> 
 
     <code [innerHtml]="html_content"></code> 
 
    </pre>`, 
 
    encapsulation: ViewEncapsulation.None, 
 
    styles: [require('highlight.js/styles/github.css')] 
 
}) 
 
export class CustomComponentsComponent { 
 
    languages = ['html', 'typescript']; 
 
    html_content = hljs.highlightAuto('<h1 class="big">Title</h1>', this.languages).value; 
 
}