I'm creating simple web app using angular 2. I have two components there. First is basically table with some data rows. When click on row is performed, data corresponding to row are displayed in the second component. Data are XML, loaded to code element. It looks something like
@Component
export class TableComponent {
items: Data[];
selectedItemsXml: string;
// ...other stuff
//when row is clicked
toggleSelectedRow(rowIndex: number) {
// ...other stuff related to change row's background color
this.selectedItemsXml = this.items[i].xml;
}
// ...other stuff again
}
//TableComponent's template
<div>
<table>
...
...*ngFor="let item of items; let i = index;"...
<tr (click)="toggleSelectedRow(i)">
<td>{{item.id}}</td>
<td>{{item.time}}</td>
</tr>
...
</table>
</div>
<xml-detail [xml]="selectedItemsXml"></xml-detail>
@Component
export class XmlDetailComponent {
@Input() xml: string;
}
//XmlDetailComponent's template
<div>
<pre><code>{{xml}}</code></pre>
</div>
Everything worked fine until I wanted to add syntax highlighting for xml. First I wanted to use plugin ng2-prism, but I had problems to make it work correctly. After I saw issues in its git repo, I threw it away. What I tried next was to create directive using highlight.js based on this post: highlight.js does not work with Angular 2. Xml is highlighted using this method, but only the first time row is clicked. When another row is clicked, new xml is not even displayed. I also tried to use prism.js but I'm getting the same behavior. Once some xml string is first time binded, displayed in code element and highlighted using either highlight.js or prism.js, it remains.
My guess is it is related with how DOM and data binding works in angular 2, because without using syntax highlighting, I'm binding and passing string to code element every time row is selected. Using highlighting causes to bind string, pass it to code element and then pretiffy it. That means there is no simple string inside code element, but a lot of styled span elements, what causes problems to load new xml string when new row is selected. I also tried to bind "pre-prettified" string using Prism.highlight(text_to_prettify), but using this method causes to display xml with all of the span elements added by Prism.
Right now, I'm scratching my head thinking about how to solve this problem. Please give me some push how could I make it work.
I would create a component that leverages prismjs.
Include the prismjs scripts including any from the components folder that you need.
Index.html
<link href="node_modules/prismjs/themes/prism.css" rel="stylesheet" />
<script src="node_modules/prismjs/prism.js"></script>
<script src="node_modules/prismjs/components/prism-core.js"></script>
<script src="node_modules/prismjs/components/prism-clike.js"></script>
<script src="node_modules/prismjs/components/prism-csharp.js"></script>
Install the latest type definition files for Prism (this will give you type-safety):
npm install @ryancavanaugh/prismjs
Note: don't install @types/prismjs - its either out-of-date or not authored correctly. The author of prismjs
recommends @ryancvanaugh/prismjs for the type definitions.
Add the folder to your typeRoots
list property in tsconfig.json
so that the typescript compiler can find it:
tsconfig.json (under compilerOptions)
"typeRoots": [
"node_modules/@types",
"node_modules/@ryancavanaugh"
]
Create a custom prism
component that calls Prism.highlight
:
prism.component.ts
/// <reference path="../node_modules/@ryancavanaugh/prismjs/prism.d.ts" />
import {
Component,
AfterViewInit,
Input,
ElementRef,
ViewChild
} from '@angular/core';
@Component({
moduleId: module.id,
selector: 'prism',
template: `
<div hidden="true" #rawContent>
<ng-content></ng-content>
</div>
<pre>
<code [innerHTML]="content">
</code>
</pre>
`
})
export class PrismComponent implements AfterViewInit {
@Input() language: string;
@ViewChild("rawContent") rawContent: ElementRef;
content: string;
constructor(private elementRef:ElementRef) {
}
ngAfterViewInit() {
this.content = Prism.highlight(this.rawContent.nativeElement.innerHTML, Prism.languages[this.language]);
}
}
Declare the Prism component in app.module:
app.module.ts
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { HttpModule } from '@angular/http';
import { AppComponent } from './app.component';
import { PrismComponent } from './prism.component';
@NgModule({
imports: [
BrowserModule,
HttpModule
],
declarations: [AppComponent, PrismComponent],
providers: [/* TODO: Providers go here */],
bootstrap: [AppComponent],
})
export class AppModule { }
Use it like this:
<prism language="csharp">
var x = 3;
class T
{{ '{' }}
{{ '}' }}
</prism>
You can try this simple angular-prism component I wrote for Angular 2/4 since ng2-prism is no longer maintained and does not work for latest angular releases.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With