[Angular] Implementing A General Communication Mechanism For Directive Interaction

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

}
复制代码

 

posted @   Zhentiw  阅读(203)  评论(0编辑  收藏  举报
编辑推荐:
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
历史上的今天:
2015-06-30 [Javascript + rxjs] Simple drag and drop with Observables
点击右上角即可分享
微信分享提示