Friday, November 30, 2018

struggling to understand Injectors for the CDK modals of Angular 6

I tried to follow this and this to no avail. In the end I just decided to solve the problem my own way with some singleton state which holds an object like so:

import { President } from '../models/president.model';
import { OverlayRef } from '@angular/cdk/overlay';
export class ModalMetadata {
   overlayRef: OverlayRef;
   president: President;
   
   public closeAction(){
      if(this.overlayRef) {
         this.overlayRef.dispose();
         this.overlayRef = null;
      }
   }
}

 
 

My service is such:

import { Injectable, OnDestroy } from '@angular/core';
import { Overlay } from '@angular/cdk/overlay';
import { President } from '../models/president.model';
import { ModalMetadata } from '../models/modalMetadata.model';
import { ModalComponent } from '../layout/modal.component';
import { ComponentPortal } from '@angular/cdk/portal';
import { Router } from '@angular/router';
import { ISubscription } from 'rxjs/Subscription';
@Injectable()
export class ModalService {
   private backingStore: ModalMetadata;
   private subscription: ISubscription;
   
   constructor(private overlay: Overlay, private router: Router) {
      this.subscription = router.events.subscribe(()=> {
         if (this.backingStore) this.backingStore.closeAction();
      });
   }
   
   public open(president:President) {
      const filePreviewPortal = new ComponentPortal(ModalComponent);
      if (!this.backingStore) this.backingStore = new ModalMetadata();
      this.backingStore.president = president;
      if (!this.backingStore.overlayRef) {
         this.backingStore.overlayRef = this.overlay.create();
         this.backingStore.overlayRef.attach(filePreviewPortal);
      }
   }
   
   public getSingletonState():ModalMetadata {
      return this.backingStore;
   }
   
   ngOnDestroy(){
      this.subscription.unsubscribe();
   }
}

 
 

I have some inversion of control in TypeScript going on and thus there is a contract for the service. It looks like this:

import { President } from '../models/president.model';
import { ModalMetadata } from '../models/modalMetadata.model';
export class ModalContract {
   constructor() {}
   public open: (president:President) => void;
   public getSingletonState: () => ModalMetadata;
}

 
 

My component that I spit out in a modal looks like this:

import { Component, OnInit } from '@angular/core';
import { ModalMetadata } from '../models/modalMetadata.model';
import { ModalContract } from '../contracts/modal.contract';
@Component({
   selector: 'modal',
   templateUrl: './modal.component.html',
   styleUrls: ['./modal.component.css']
})
export class ModalComponent implements OnInit {
   private modalMetadata: ModalMetadata;
   
   constructor(public modalContract: ModalContract) {}
   
   ngOnInit() {
      this.modalMetadata = this.modalContract.getSingletonState();
   }
   
   close() {
      this.modalMetadata.closeAction();
   }
}

 
 

The template for the component is super simple. You will note that you may click an X to close to modal! Also you may have noticed above that the modal closes itself if you navigate away elsewhere.

{{ modalMetadata.president.Name}}... <a (click)="close()">X</a>

 
 

To use this stuff just call the open method in the service. This is all an better bake out of what I originally wrote about here.

 
 

Addendum 12/1/2018: I guess the "singleton state" isn't really a singleton as the state mutates. No... I spoke too soon. A singleton doesn't have to be constant. It's OK.

No comments:

Post a Comment