【问题标题】:Data-binding ng2 component's template only set OnInit数据绑定 ng2 组件的模板只设置了 OnInit
【发布时间】:2016-12-21 04:36:25
【问题描述】:

我有一个 Angular 2 (RC5) 组件,它进行 HTTP 调用并将结果设置为组件的模板。我想将一个值注入到 HTTP 调用返回的 HTML 中。例如,返回的 HTML 中的其中一行是:

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

但是,它完全按原样呈现,没有注入 chapterURL。大概是因为初始化过程中没有设置模板吧?如果是这样,我应该如何将这些动态值注入到模板中?

这是组件。

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

编辑:

我已将 http 调用返回的源 html 文件更改为:

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

然后将组件的模板改成:

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

其中rawHtml 是使用DomSanitizationService 上的bypassSecurityTrustHtml() 函数清理内容的管道,但是我仍然得到相同的结果,呈现的结果是:

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

如果我对浏览器中选择的组件执行ng.probe($0),则返回的结果对象具有属性,但列出的唯一属性是innerHTML,仅此而已...

【问题讨论】:

  • 在哪里使用了step@Input 变量?
  • @candidJ this.step在构造url时使用
  • 我的意思是说它是从哪里渲染的...任何父组件将值传递给步骤?
  • @candidJ 是的,该组件被称为例如&lt;codestep [step]="2.1"&gt;&lt;/codestep&gt;
  • &lt;a class="d2h-file-name" [href]="chapterURL"&gt;app/views/login/login.xml&lt;/a&gt; 有帮助吗?

标签: javascript http angular typescript


【解决方案1】:

2 种方法

方法一——搜索替换

这很简单,如果数据在初始化时只需要更新一次。

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

方法二——动态组件

Angular 2 不支持组件模板运行时更新。

innerHTML 不会满足您的要求,因为 Angular2 不会解析它的内容。因此,innerHTML 中的数据绑定将不起作用。

为了归档运行时模板更新,或者更准确地说,运行时模板生成是使用动态组件。

Radim Köhler 在此处提供了详细的示例答案: https://stackoverflow.com/a/38888009/1810391

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

以下是我整理的一个非常简约的示例:

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

【讨论】:

    【解决方案2】:

    我没有测试过这个。试着告诉我进展如何

    import {Component, Output, Input,AfterViewInit} from '@angular/core';
    
     export class codeStepComponent implements AfterViewInit {
         ngAfterViewInit() {
           this.content.innerHTML.replace('{{chapterURL}}', this.chapterURL);
        }
      } 
    

    这假设您在页面上的 {{ChapterUrl}} 上有一个实例,并且该占位符将在视图初始化后以老式方式替换。

    【讨论】:

    • 如果ChapterUrl不需要动态更改,这实际上要简单得多。或者在将结果分配给content之前解析一次。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-15
    • 1970-01-01
    • 1970-01-01
    • 2018-07-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多