Angular 9 ng-内容动态更新

Angular 9 ng-content dynamic update

如何通过更新内容元素上的选择器来更新 ng-content?

我在 app.component.html 中有代码:

<my-slider>
  <img src="../../assets/logo1.png" />
  <img src="../../assets/logo2.png" />
</my-slider>

这是代码 my-slider.component.ts:

@Component({
  selector: 'my-slider',
  template: '<ng-content select=".render" ></ng-content>
             <button (click)="render()"> Show</button>',
  styleUrls: ['./slider.component.css']
})
export class SliderComponent {
  @ContentChildren(ImgComponent) img: QueryList<ImgComponent>;
  constructor() { }
  render() {
    this.img.last.show();
  }
}

和ImgComponent.ts

@Component({
  selector: 'img',
  template: '',
})
export class ImgComponent {
  render: boolean = false;

  constructor(
    private elRef: ElementRef,
    private renderer: Renderer2
  ) { }

  show() {
    this.render = true;
    this.renderer.addClass(this.elRef.nativeElement, 'render');
  }
  hide() {
    this.render = false;
    this.renderer.removeClass(this.elRef.nativeElement, 'render');
  }
}

当我点击按钮时,一个 class 被添加到元素中,但是 ng-content 永远不会更新。我能以某种方式让它工作吗?或者我如何过滤 ng-content 中的组件?

我无法回答您关于 ng-content 更新的问题,并且 ng-content 是 Angular 恕我直言的一个文档不足的功能。但我确实有解决问题的办法:

<img 
  *ngFor="let img of images"
  [style.display]="img.render ? undefined : 'none'"
  [src]="img.src"
></img>

然后在您的组件上创建一个 public images: {render: boolean, src: string}[] 并切换项目的 render 属性。

您需要访问组件中的宿主元素,因为您提出的解决方案将您的自定义 img 组件封装到本机组件中。我建议在这里使用自定义属性指令。参见 Stackblitz example

谢谢大家的回复。这是我一直在寻找的解决方案:

我向 img 添加了一个结构指令,而不是使其成为 angular 组件,现在 app.component.html 看起来像:

<app-slider>
  <img *myImg scr="../../assets/logo1.png" />
  <img *myImg scr="../../assets/logo1.png" />
</app-slider>

my-slider.component.ts 并没有真正改变。我只是删除 select='.render' 无论如何它是:

@Component({
  selector: 'app-slider',
  template: `<ng-content></ng-content>
            <br/>
            <button (click)="render()">Toggle</button>`,
})
export class SliderComponent {
  @ContentChildren(ImgDirective) img: QueryList<ImgDirective>;
  constructor() { }
  ngAfterContentInit() {
    this.img.first.show();
  }
  render() {
    if (!this.img.last.render) {
      this.img.last.show();
    } else {
      this.img.last.hide();
    }
  }
}

最后我的结构指令 ImgDirective:

import { Directive, TemplateRef, ViewContainerRef } from '@angular/core';

@Directive({
  selector: '[myImg]'
})
export class ImgDirective {
  render: boolean = false;
  constructor(
    private viewContainer: ViewContainerRef,
    private templateRef: TemplateRef<any>,
  ) { }

  ngOnInit() {
    this.viewContainer.clear();
  }

  show() {
    this.render = true;
    this.viewContainer.createEmbeddedView(this.templateRef)
  }

  hide() {
    this.render = false;
    this.viewContainer.clear();
  }
}

这里是活生生的例子:link