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
      ) { }
    
    }
  • 相关阅读:
    [GO]使用bufio的文件读取方式
    php开发工程师面必问题
    一位资深php程序员在北京的面试30个题目
    GIT 分支管理:创建与合并分支、解决合并冲突
    linux下挂在u盘,移动硬盘的方法,转移服务器资料的时候,使用移动硬盘什么最方便了
    php后台对接ios,安卓,API接口设计和实践完全攻略,涨薪必备技能
    navicat 官方使用手册,中文版,快捷键大全
    Memcached之缓存雪崩,缓存穿透,缓存预热,缓存算法
    Memcache 笔记(2)
    Memcache笔记(1)
  • 原文地址:https://www.cnblogs.com/Answer1215/p/7100393.html
Copyright © 2011-2022 走看看