Búsqueda de sitios web

javascript - Vínculo de datos en la plantilla del componente ng2 solo configurado en OnInit


Tengo un componente de Angular 2 (RC5) que realiza una llamada HTTP y establece el resultado como la plantilla del componente. Quiero inyectar un valor en el HTML que se devuelve mediante la llamada HTTP. Por ejemplo, una de las líneas en el HTML devuelto es:

<a class="d2h-file-name" href="{{chapterURL}}">app/views/login/login.xml</a>

Sin embargo, eso se representa exactamente tal como está, sin haber inyectado el chapterURL. Presumiblemente, esto se debe a que la plantilla no se establece durante el proceso de inicialización. Si es así, ¿cómo debería inyectar estos valores dinámicos en las plantillas?

Aquí está el componente.

@Component({
    selector: 'codestep',
    template: `<div class="codestep" [innerHTML]="content"></div>`
})
export class codeStepComponent {
    @Input() step: string;
    private content: string = '';
    private chapterURL;

    constructor(private route: ActivatedRoute, private http: Http) { }

    ngOnInit() {
        this.chapterURL = './diff/' + this.step + '.html';
        this.getChapter()
            .subscribe(
            chapterContent => this.content = chapterContent,
            error => this.errorMessage = <any>error);
    }

    getChapter(): Observable<any> {
        return this.http.get(this.chapterURL)
            .map(this.extractData)
            .catch(this.handleError);
    }
    private extractData(res: Res) {
        let body = res._body;
        return body;
    }
    //Error handling function here...
}

Editar :

He cambiado el archivo html de origen que se devuelve por la llamada http, a:

<a class="d2h-file-name" href={{chapterURL}}>app/views/login/login.xml</a>

y luego cambió la plantilla del componente a:

template: `<div class="codestep" [innerHTML]="content|rawHtml"></div>`

donde rawHtml es un pipe que sanitiza el contenido con la función bypassSecurityTrustHtml() en el DomSanitizationService, sin embargo, todavía obtengo el mismo resultado, el resultado renderizado es:

<a class="d2h-file-name" href="gitURL">app/views/login/login.xml</a>

si hago ng.probe($0) con el componente seleccionado en el navegador, entonces el objeto resultante devuelto tiene propiedades, pero la única propiedad que se muestra es innerHTML, nada más...

Respuesta #1

2 métodos

Método 1 - buscar y reemplazar

Esto es simple y fácil, si los datos solo necesitan ser actualizados una vez durante la inicialización.

ngOnInit() {
    this.chapterURL = './diff/' + this.step + '.html';
    this.getChapter()
        .subscribe(
        chapterContent:string => {

            // Pre-process the content
            processedContent = chapterContent.replace('{{chapterURL}}',this.chapterURL);

            this.content = processedContent;
        },
        error => this.errorMessage = <any>error);
}

Método 2 - componente dinámico

Angular 2 no admite la actualización en tiempo de ejecución de la plantilla del componente.

innerHTML no cumplirá con su requisito ya que Angular2 no analizará su contenido. Por lo tanto, la vinculación de datos dentro de innerHTML no funcionará.

Para archivar la actualización de la plantilla en tiempo de ejecución, o más precisamente, la generación de la plantilla en tiempo de ejecución se está utilizando un componente dinámico.

Aquí hay una respuesta detallada con un ejemplo de Radim Köhler: https://stackoverflow.com/a/38888009/1810391

http://plnkr.co/edit/iXckLz?p=preview

A continuación se muestra un ejemplo muy minimalista que preparé:

cf.com.ts

import { Component, ComponentRef, ViewChild, ViewContainerRef } from '@angular/core';

import { RuntimeCompiler } from '@angular/compiler';

import { CfModule } from './cf.module';

@Component({
    selector: 'cf-com',
    template: `
        <h1>{{title}}</h1>
        <button (click)="template1()">Template 1</button>
        <button (click)="template2()">Template 2</button>
        <button (click)="moreChild()">More Child</button>
        <template [ngIf]="childRef" #child></template>`
})
export class CfCom {
    title = 'Component Factory Test';

    // reference for html element with #child tag
    @ViewChild('child', { read: ViewContainerRef }) protected childComTarget: ViewContainerRef;
    // Child component reference
    protected childRef: ComponentRef<any>;

    constructor(private compiler: RuntimeCompiler) { }

    // Child Input. Use object, not basic type
    childInput = { counter: 0 };

    // Click to get more children
    moreChild() {
        this.childInput.counter++;
    }

    // Click to use template 1
    template1() {
        let t = 'Child:{{j.counter}}';
        this.createChild(t);
    }

    // Click to use template 1
    template2() {
        let t = 'Children:{{j.counter}}';
        this.createChild(t);
    }

    createChild(t: string) {
        // Destroy child if exist
        if (this.childRef) {
            this.childRef.destroy();
            this.childRef = null;
        }

        // cf-child class
        @Component({
            selector: 'cf-child',
            template: t // template from parameter t
        })
        class CfChildCom {
            j; // will be bind with parent childInput, see below
        }

        this.compiler.compileComponentAsync<any>(CfChildCom, CfModule)
            .then(factory => {
                this.childRef = this.childComTarget.createComponent(factory, 0);

                // This is how parent variable bind with child variable
                this.childRef.instance.j = this.childInput;
            });
    }
}

cf.module.ts

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { COMPILER_PROVIDERS } from '@angular/compiler';

import { CfCom } from './cf.com';

@NgModule({
    imports: [BrowserModule],
    exports: [CfCom],
    providers: [COMPILER_PROVIDERS],
    declarations: [CfCom]
})
export class CfModule { }

Respuesta #2

No he probado esto. Inténtalo y dime cómo te va

import {Component, Output, Input,AfterViewInit} from '@angular/core';

 export class codeStepComponent implements AfterViewInit {
     ngAfterViewInit() {
       this.content.innerHTML.replace('{{chapterURL}}', this.chapterURL);
    }
  } 

Esto asume que tienes una instancia en {{ChapterUrl}} en tu página y este marcador de posición se reemplazará a la manera antigua después de que la vista haya sido inicializada.