创建对其参数应用2种方式绑定的结构化指令

时间:2019-06-13 17:25:03

标签: angular angular-directive

我目前需要在一些地方执行以下操作,以确保对话框仅在打开时才出现在DOM中。

<vcd-modal *ngIf="modalOpen" [(open)]="modalOpen" ...>

我想为语法糖创建一个指令,该指令看起来像<vcd-modal *vcdModalOpen[modalOpen]>,它为我处理了双重绑定。我有以下代码

import {AfterViewChecked, Directive, EmbeddedViewRef, Input, TemplateRef, ViewContainerRef} from "@angular/core";

@Directive({
    selector: "vcd-modal[vcdModalOpen]"
})
export class ModalOpenDirective implements AfterViewChecked {

    private hasView = false;

    // Unsure how to get this, this is the component where 
    // `this.modalOpen` is defined
    private parent: any;

    constructor(
        private modal: VcdModalComponent,
        private templateRef: TemplateRef<any>,
        private viewContainer: ViewContainerRef) {

    }

    @Input() set vcdModalOpen(condition: boolean) {
        if (!condition && !this.hasView) {
            this.viewContainer.clear();
            this.hasView = false;
            // Need to unsubscribe from previously created components
        } else if (condition && this.hasView) {
            this.viewContainer.createEmbeddedView(this.templateRef);
            this.hasView = true;

            // Bind one from modal to the parent
            this.modal.openChange.subscribe((open) => {
                this.parent.modalOpen = open;     
            });

            // Bind from the parent to the modal
            const oldNgOnChanges = this.parent.ngOnChanges;
            this.parent.ngOnChanges = (changes: SimpleChanges) => {
                oldNgOnChanges.call(this, changes);
                this.model.open = this.parentModalOpen;
            }
        }
    }

}

由于以下原因,它不起作用:

  • 我无法知道父母是谁,所以我可以设置其modalOpen标志
  • 父级的modalOpen状态的属性名称可以是任何东西,不一定是modalOpen,但表达式已由Angular求值

我认为我可以将父项和属性名称作为字符串传递,但是我将失去类型安全性,最终将需要比带有*ngIf和双重绑定的示例更多的代码。 / p>

有没有一种方法可以实现我正在寻找的语法糖?

1 个答案:

答案 0 :(得分:0)

您将指令传递给主题。当指令接收到主题时,对话框将打开,而当对话框关闭时,指令将发出结果。

component.ts

@Component({})
export class MyComponent {
  public modalOpen$: Subject<Subject<any>> = new Subject();

  public function open() {
      const s = new Subject();
      s.subscribe(result => {
          console.log('dialog result', result);
      });
      this.modalOpen$.next(s);
  }
}

component.html

<vcd-modal *ngIf="modalOpen$ | async">

现在您更改指令以使用该主题。

@Directive({...})
export class ModalOpenDirective implements AfterViewChecked {
    private hasView = false;

    constructor(
        private modal: VcdModalComponent,
        private templateRef: TemplateRef<any>,
        private viewContainer: ViewContainerRef) {
    }

    @Input() set vcdModalOpen(parent: Subject<any>) {
        if (!parent && !this.hasView) {
            this.viewContainer.clear();
            this.hasView = false;      
        } else if (parent && this.hasView) {
            this.viewContainer.createEmbeddedView(this.templateRef);
            this.hasView = true;

            this.modal.openChange.subscribe((open) => {
            // ^^ I'm not sure what this is but emit it back to the parent
                parent.next(open);     
            });
        }
    }
}

以上内容基于主题对象为 truthy 的想法进行工作,并将显示模板。当指令发出结果时,父组件然后可以发出undefined作为下一个删除模板的值。