[Angular] Implementing A General Communication Mechanism For Directive Interaction

本文介绍如何在 Angular 中实现模态框的关闭功能。通过创建 AuModalService 服务来协调 AuModal 组件与 AuModalOpenOnClick 指令间的通信。利用 Observable 实现关闭操作,并通过 AuModalOpenOnClick 指令订阅关闭事件。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

We have modal implement and now we want to implement close functionality. 

Becuase we use a structure directive to do open modal on click functionality. So as you can see, the directive and modal component is spreated. We need to have some way to communcation between directive and component. 

  <ng-template [auModalOpenOnClick]="[loginButton, signUpButton]">
    <au-modal class="auth-modal" [body]="newModelBody">
       <!-- modal body -->
    </au-modal>
  </ng-template>

 

One general communction mechanism is though serivce. 

So we need to create a service which only for AuModal component:

import {NgModule, ModuleWithProviders} from '@angular/core';
import {AuModalComponent} from './au-modal.component';
import {CommonModule} from '@angular/common';
import { AuModalOpenOnClickDirective } from './au-modal-open-on-click.directive';
import {AuModalService} from 'app/au-modal/au-modal.service';

@NgModule({
  declarations: [AuModalComponent, AuModalOpenOnClickDirective],
  imports: [
    CommonModule
  ],
  exports: [
    AuModalComponent,
    AuModalOpenOnClickDirective
  ]
})
export class AuModalModule {

  /*
  * Inject AuModuleService here instead of global providers is for lazy loading
  * to prevent duplicate serivce name.
  * */
  static forRoot(): ModuleWithProviders {
    return {
      ngModule: AuModalModule,
      providers: [
        AuModalService
      ]
    }
  }
}

Because we don't want it to be global, it might affect lazy loading, have naming conflicts with other third party libs. Therefore we use 'forRoot' static method on the AuModalModule. This approach is good for lazy loading.

 

Service:

Service is Observable based implementation. It mean we gonna have one public method call 'close' and an public observable variable call 'close$'.

Once close() method was called, 'close$' can get notifiied.

import { Injectable } from '@angular/core';
import {Observable} from 'rxjs/Observable';
import {Subject} from 'rxjs/Subject';

@Injectable()
export class AuModalService {

  private subject = new Subject();
  close$: Observable<any> = this.subject.asObservable();
  constructor() { }

  close() {
    this.subject.next();
  }

}

 

AuModal component: We want user click outside modal body to close the modal, so we bind 'closeModal' function tot he overlay wrapper. And also we don't want user click modal body itself to trigger the close event also. So we have second method called 'cancelCloseModal' to stop event propagation.

<div class="modal-overlay" (click)="closeModal()">

  <div class="modal-body" (click)="cancelCloseModal($event)">

    <ng-container *ngIf="body; else projectionBody">
      <ng-container *ngTemplateOutlet="body"></ng-container>
    </ng-container>

    <ng-template #projectionBody>
      <ng-content></ng-content>
    </ng-template>

  </div>

</div>
  closeModal() {
    this.auModelService.close();
  }

  cancelCloseModal(evt: KeyboardEvent) {
    evt.preventDefault();
    evt.stopPropagation();
  }

 

Now the only thing leave to do is subscribe the 'close$' observable inside the directive, once event was triggered, we clear the component.

Directive:

import {Directive, Input, OnInit, TemplateRef, ViewContainerRef} from '@angular/core';
import {AuModalService} from './au-modal.service';

@Directive({
  selector: '[auModalOpenOnClick]'
})
export class AuModalOpenOnClickDirective implements OnInit{
  ngOnInit(): void {
    this.auModalService.close$
      .subscribe(() => this.viewContainer.clear());
  }

  @Input()
  set auModalOpenOnClick (els) {

    let elements: HTMLBaseElement[];

    if(Array.isArray(els)) {
      elements = els;
    } else {
      elements = [els];
    }

    elements.forEach(el => {
      el.addEventListener('click', () => {
        this.viewContainer.clear();
        this.viewContainer.createEmbeddedView(this.template);
      });
    });
  }

  constructor(
    private template: TemplateRef<any>,
    private viewContainer: ViewContainerRef,
    private auModalService: AuModalService
  ) { }

}

 

转载于:https://www.cnblogs.com/Answer1215/p/7100393.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值