Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
333 views
in Technique[技术] by (71.8m points)

javascript - Data-binding ng2 component's template only set OnInit

I have an angular 2 (RC5) component which makes an HTTP call and sets the result as the template of the component. I want to inject a value into the HTML that is returned by the HTTP call. so for example, one of the lines in the returned HTML is:

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

However, that is rendered exactly as is, without having the chapterURL injected. Presumably, this is because the template isn't set during the initialization process? If so, How should I inject these dynamic values into the templates?

Here's the component.

@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...
}

Edit:

I have changed the source html file which is returned by the http call, to:

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

and then changed the component's template to:

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

where rawHtml is a pipe that sanitises the content with the bypassSecurityTrustHtml() function on the DomSanitizationService however, I still get the same result, the rendered result is:

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

if I do ng.probe($0) with the component selected in the browser, then the returned resultant object has properties, but the only property listed is innerHTML, nothing else...

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

2 Methods

Method 1 - search and replace

This is simple and easy, if the data only need to be updated once during initialization.

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);
}

Method 2 - dynamic component

Angular 2 does not support component template run time update.

innerHTML will not meet your requirement as Angular2 will not parse the content of it. So data binding within innerHTML will not work.

To archive run time template update, or more precisely, run time template generation is using dynamic component.

There is a detail answer with example here by Radim K?hler: https://stackoverflow.com/a/38888009/1810391

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

Following is a very minimalistic example I put together:

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 { }

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...