Search code examples
javascriptangularng-content

Angular 9 ng-content dynamic update


how i can update ng-content by updating selector on content elements?

I have code in app.component.html:

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

Here's the code 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();
  }
}

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

When I click the button, a class is added to the element, but ng-content never updates. Can i somehow make it work? Or how I can filter components in ng-content?


Solution

  • Thank you, all for your responce. Here is solution i had been looking for:

    I had added a structual directive to img instead of making it angular component and now app.component.html looks like:

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

    my-slider.component.ts is not realy changed. I just remove select='.render' anyway here it is:

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

    And finaly my structual directive 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();
      }
    }
    

    Here live example: link