zoukankan      html  css  js  c++  java
  • [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
      ) { }
    
    }
  • 相关阅读:
    沉淀再出发:在python3中导入自定义的包
    沉淀再出发:java中的equals()辨析
    沉淀再出发:web服务器和应用服务器之间的区别和联系
    沉淀再出发:jetty的架构和本质
    沉淀再出发:dubbo的基本原理和应用实例
    沉淀再出发:OpenStack初探
    沉淀再出发:Spring的架构理解
    沉淀再出发:关于IntelliJ IDEA使用的一些总结
    沉淀再出发:spring boot的理解
    沉淀再出发:Bean,JavaBean,POJO,VO,PO,EJB等名词的异同
  • 原文地址:https://www.cnblogs.com/Answer1215/p/7100393.html
Copyright © 2011-2022 走看看