angular2检测ng-content的变化

时间:2017-11-15 11:34:36

标签: javascript angular

有没有办法检测ng-content的变化?

@Component({
    selector: 'example',
    template: `<ng-content></ng-content>`
})
export class Example {}

@Component({
    selector: 'test',
    template: `
        <example>
            <div *ngFor="let el of elements">{{el}}</div>
        </example>`
})
export class Test {
    elements = [1, 2, 3];

    ngOnInit() {
        setInterval(() => this.elements[0] += 10, 3000);
    }
}

当我的ng-content发生变化时,我想在Example类中获取一些信息。

这是plunker

6 个答案:

答案 0 :(得分:5)

最简单的解决方案是使用cdkObserveContent指令。 首先,您必须添加拥有组件ObserversModule

的模块的导入
import {ObserversModule} from '@angular/cdk/observers';

@NgModule({
  imports: [
    /* ...other modules you use... */
    ObserversModule
  ],

/* ... */
})
export class MyModule { }

然后在组件的模板中:

<div (cdkObserveContent)="onContentChange($event)">
  <ng-content></ng-content>
</div>

每次内部内容以某种方式发生更改时,都会触发该事件,并且传递给该函数的值是一个包含有关更改内容的所有详细信息的数组。可以在target.data中找到已更改的数据的值。

在您的component.ts中:

onContentChange(changes: MutationRecord[]) {
   // logs everything that changed
   changes.forEach(change => console.log(change.target.data));
}

此外,您可以将其用作为您提供Observable<MutationRecord[]>

的服务

答案 1 :(得分:3)

我的项目解决方案是监控内容的innerHTML。此示例来自显示模板内容的工具提示。我真的不喜欢这个解决方案,并乐意提供一个不同/更好的解决方案。只要有变化,这就会发出。

/// tooltip.component.html
<div class="tooltip" [class.hidden]="hidden">
    <div #content>
        <ng-content></ng-content>
    </div>
</div>

///tooltip.component.js
import { AfterContentChecked, AfterContentInit, Component, ElementRef, EventEmitter, Output, ViewChild } from "@angular/core";

@Component({
    selector: "example",
    templateUrl: "./tooltip.component.html",
    styleUrls: ["./tooltip.component.scss"]
})
export class TooltipComponent implements AfterContentInit, AfterContentChecked {    
    @ViewChild("content") contentWrapper: ElementRef;
    content = "";
    @Output() public readonly contentChanged = new EventEmitter<string>();

    ngAfterContentInit(): void {
        this.content = this.contentWrapper.nativeElement.innerHTML;
        this.contentChanged.emit(this.content);
    }

    ngAfterContentChecked(): void {
        const c = this.contentWrapper.nativeElement.innerHTML;
        if (c !== this.content) {
            this.content = c;
            this.contentChanged.emit(this.content);
        }
    }
}

答案 2 :(得分:1)

假设您要添加ng-content,以检测ItemComponent中的更改。

代码为:

import { QueryList, ContentChildren, AfterViewInit } from '@angular/core';

export class TestComponent implements AfterViewInit  {

    @ContentChildren(ItemComponent)
    public itemList:QueryList<ItemComponent>;


    public ngAfterViewInit() : void {
        this.itemList.changes.subscribe(() => {
            // put your logi here
        });
    }

}

注释:
根据{{​​3}},您必须等待ngAfterViewInit才能访问QueryList,因此不能在ngOnInit上使用它。

请参见ContentChildren documentation,以查看此类提供给您的所有其他属性。

答案 3 :(得分:0)

我已经找到了解决方案,但我认为这可能无法满足所有人的需求。首先,在React world上,对待嵌套组件子元素(毕竟,ng-content就是这样)非常容易,我认为为Angular提供更健壮的解决方案也很好。

我的解决方案基于Material Angular Icon,您将在此处找到以下代码: https://github.com/angular/material2/blob/master/src/lib/icon/icon.ts

按照MatIcon的方法,我希望创建一个图标组件,其中所需图标的名称通过ng-content(如箭头顶部)传递。

因此,我希望观察ng-content何时发生变化,以便可以更新span类名。

解决方案只是将呈现为ng-content的数据链接到@Input,然后是getter。

因此,只要ng-content发生变化,Angular也会更新其组件输入。

希望这看起来很清楚。

@Component({
 selector: 'fa-icons',
 template: `
 <span #templateRef class="template">
  <ng-content></ng-content>
 </span>

 <span [className]="iconName" [ngStyle]="ngStyle">
 </span>
 `,
 styles: [`
   :host > span.template {
     display: none;
   }
 `]
})
export class FaIconsComponent {
 @ViewChild('templateRef') templateRef: ElementRef;
 @Input() name: String;
 @Input() ngStyle: StyleSheetList;
 @Input()
 get iconName() {
   const text = this.templateRef.nativeElement.textContent.trim();
   return `fa-${text}`;
  }
}

答案 4 :(得分:0)

使用AfterContentChecked接口:

constructor(private cd: ChangeDetectorRef) { 
}
ngAfterContentChecked():void{
  this.cd.markForCheck();
}

有关更多信息,请查看https://angular.io/api/core/AfterContentChecked

答案 5 :(得分:-1)

如果您每次绑定数据更新时都尝试完成某些操作,则可以使用public static void perturbacaoAES() throws Exception { Security.addProvider(new FlexiCoreProvider()); Cipher cipher = Cipher.getInstance("AES128_CBC", "FlexiCore"); KeyGenerator keyGen = KeyGenerator.getInstance("AES", "FlexiCore"); SecretKey secKey = keyGen.generateKey(); cipher.init(Cipher.ENCRYPT_MODE, secKey); FileInputStream fis = new FileInputStream("Zero.txt"); FileOutputStream fos = new FileOutputStream("ZeroCifrado.txt"); try (CipherOutputStream cos = new CipherOutputStream(fos, cipher)) { byte[] block = new byte[8]; int i; while ((i = fis.read(block)) != -1) { cos.write(block, 0, i); } } fis.close(); fos.close(); byte[] newKey = secKey.getEncoded(); newKey[0] ^= 1 << 1; secKey = new SecretKeySpec(newKey, "AES128_CBC"); cipher.init(Cipher.ENCRYPT_MODE, secKey); FileInputStream nfis = new FileInputStream("Zero.txt"); FileOutputStream nfos = new FileOutputStream("ZeroChaveCifrado.txt"); try (CipherOutputStream cos = new CipherOutputStream(nfos, cipher)) { byte[] block = new byte[8]; int i; while ((i = nfis.read(block)) != -1) { cos.write(block, 0, i); } } } 生命周期钩子。查看docs了解详情。