2

I am trying to write a custom Structural Directive that makes use of an ngrx store. Inside of the store, I have a flag that tells me whether or not we should show some components. I want to have my custom directive subscribe to that store, and render components based on whether that flag is true or whether that flag is false but the component has data that should be rendered. Code below:

@Directive({ selector: '[showIfExists]' })
export class ShowIfExistsDirective {

  showEmpty$ = this.store.select(getShowHideState).subscribe((value) => {
    this.showEmpty = value;
  });
  showEmpty: boolean;

  constructor(
    private templateRef: TemplateRef<any>,
    private viewContainer: ViewContainerRef,
    private store: Store<AppState>) {
  }

  ngOnDestroy() {
    this.showEmpty$.unsubscribe();
  }

  @Input() set showIfExists(condition: boolean) {
    if (this.showEmpty || (!this.showEmpty && condition)) {
      this.viewContainer.createEmbeddedView(this.templateRef);
    } else {
      this.viewContainer.clear();
    }
  }
}

What I end up seeing is that the subscription updates my showEmpty attribute properly, however, the set showIfExists does not respond to the change on showEmpty, unless showEmpty is true.

Steve
  • 226
  • 3
  • 12

1 Answers1

3

You will need to create or clear the view within the subscription. I recommend, that you create another Observable (BehaviorSubject) from the input.

@Directive({ selector: '[showIfExists]' })
export class ShowIfExistsDirective {

  showEmpty$: Observable<boolean> = this.store.select(getShowHideState);
  showIfExists$: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);

  constructor(
    private templateRef: TemplateRef<any>,
    private viewContainer: ViewContainerRef,
    private store: Store<AppState>) {

    combineLatest([this.showEmpty$, this.showIfExists$]).pipe(
      distinctUntilChanged(),
      map(([showEmpty, showIfExists]) => showEmpty || condition), // !showEmpty is btw redundant
      // don't forget to unsubscribe your way
    ).subscribe(activate => {
      if (activate) this.viewContainer.createEmbeddedView(this.templateRef)
      else this.viewContainer.clear();
    });
  }

  @Input() set showIfExists(condition: boolean) {
    this.showIfExists$.next(condition);
  }
}
MoxxiManagarm
  • 8,735
  • 3
  • 14
  • 43