Создать структурную директиву, которая применяет двухстороннее связывание к своим параметрам - PullRequest
1 голос
/ 13 июня 2019

Мне нужно сделать следующее в нескольких местах, чтобы диалоги присутствовали в 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 и двойной привязкой.

Есть ли способ добиться этого синтаксического сахара, который я ищу?

1 Ответ

0 голосов
/ 13 июня 2019

Вы передаете директиву предмет.Когда директива получает тему, диалоговое окно открывается, а когда диалоговое окно закрывается, директива выдает результат.

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

Вышеприведенное действие основано на идее, что объект субъекта истинен , и покажет шаблон.Когда директива выдает результат, родительский компонент может затем выдать undefined в качестве следующего значения, которое удалит шаблон.

...