Estoy creando una aplicación web simple usando angular 2. Tengo dos componentes allí. Primero es básicamente una tabla con algunas filas de datos. Cuando se hace clic en la fila, los datos correspondientes a la fila se muestran en el segundo componente. Los datos son XML, cargados en el elemento de código. se parece a algo
@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>Todo funcionó bien hasta que quise agregar resaltado de sintaxis para xml. Primero quise usar el plugin ng2-prism, pero tuve problemas para hacerlo funcionar correctamente. Después de ver problemas en su repositorio de git, lo tiré. Lo que intenté a continuación fue crear una directiva usando Highlight.js basada en esta publicación: Highlight.js no funciona con Angular 2 . Xml se resalta con este método, pero solo se hace clic en la primera fila. Cuando se hace clic en otra fila, ni siquiera se muestra el nuevo xml. También traté de usar prism.js pero obtengo el mismo comportamiento. Una vez que alguna cadena xml se vincula por primera vez, se muestra en el elemento de código y se resalta con resaltado.js o prism.js, permanece.
Supongo que está relacionado con la forma en que DOM y el enlace de datos funcionan en angular 2, porque sin usar el resaltado de sintaxis, estoy enlazando y pasando una cadena al elemento de código cada vez que se selecciona una fila. Usando las causas de resaltado para vincular la cadena, pásela al elemento de código y luego utilícela. Eso significa que no hay una cadena simple dentro del elemento de código, sino una gran cantidad de elementos de intervalo con estilo, lo que causa problemas para cargar una nueva cadena xml cuando se selecciona una nueva fila. También traté de vincular una cadena "pre-embellecida" usando Prism.highlight (text_to_prettify), pero usar este método hace que se muestre xml con todos los elementos de intervalo agregados por Prism.
En este momento, estoy rascándome la cabeza pensando en cómo resolver este problema. Por favor, dame un empujón, ¿cómo podría hacer que funcione?
Crearía un componente que aproveche prismjs.
Incluya los scripts de prismjs, incluido cualquiera de la carpeta de componentes que necesite.
índice.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>Instale los últimos archivos de definición de tipo para Prism (esto le dará seguridad de tipo):
npm install @ryancavanaugh/prismjs Nota: no instale @types/prismjs; está desactualizado o no se creó correctamente. El autor de prismjs recomienda @ryancvanaugh/prismjs para las definiciones de tipos.
Agregue la carpeta a su propiedad de lista typeRoots en tsconfig.json para que el compilador de mecanografiado pueda encontrarla:
tsconfig.json (en opciones de compilador)
"typeRoots": [ "node_modules/@types", "node_modules/@ryancavanaugh" ] Cree un componente de prism personalizado que llame a Prism.highlight :
prisma.componente.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 el componente Prism en app.module:
aplicación.módulo.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 { }Úsalo así:
<prism language="csharp"> var x = 3; class T {{ '{' }} {{ '}' }} </prism>Puede probar este componente de prisma angular simple que escribí para Angular 2/4 ya que ng2-prism ya no se mantiene y no funciona para las últimas versiones angulares.
Utilizo la solución PixelBits, con pocos cambios, primero asegúrese de no probar el componente de prisma en el archivo App.component.ts, obtendría un error de "Vista cambiada después de que se haya verificado" y ngAfterViewInit() no sería llamado si recargas la página. Así que haga un enrutamiento básico y una página y pruebe su componente de prisma dentro de esa nueva página. A continuación, si desea utilizar el complemento de número de línea, Prism.highlight no funcionará. Necesita usar Prism.highlightElement. Además, con la solución PixelBits obtiene un espacio vacío antes y después de su código. No olvide cambiar la URL de la ruta de referencia para que coincida con su proyecto.
t:
export class PrismComponent implements OnInit,AfterViewInit { @Input() language: string; @ViewChild("rawContent") rawContent: ElementRef; @ViewChild("codeRef") codeRef: ElementRef; content: string; myClass:string; constructor( private elementRef:ElementRef, ) { } ngOnInit(){ this.myClass = "language-" + this.language; } ngAfterViewInit() { // trim because ng-content add space this.content = this.rawContent.nativeElement.innerHTML.trim(); // make line number plugin work. Prism.highlightElement(this.codeRef.nativeElement,true); } }y HTML:
<pre class="line-numbers"><code #codeRef [innerHTML]="content" [class]="myClass"></code></pre> <div style="display: none;" hidden="true" #rawContent> <ng-content></ng-content> </div>Además, no uso npm para obtener prism.js, pero lo tomé del sitio web oficial de prism (el complemento para el número de línea está integrado dentro de prism.js).