how to close material overlay from within componentPortal instance
Asked Answered
H

3

6

I had to pass the overlayRef manually, is there a nicer way to include it in the components constructor with DI?

service code:

display() {
    const overlayRef = this.overlay.create({
      positionStrategy: this.overlay.position().global().top(),
    });
    const portal = new ComponentPortal(ErrorsListBottomSheetComponent);
    this.ref = overlayRef.attach<ErrorsListBottomSheetComponent>(portal);
    this.ref.instance.overlayRef = overlayRef;
    overlayRef.backdropClick().subscribe(() => {
      overlayRef.detach();
    });

  }

component code:

export class ErrorsListBottomSheetComponent implements OnInit {
  overlayRef: OverlayRef; -- REMOVE THIS--

  constructor(
-- ADD SOMETHING HERE --
  ) {}

close() {
    if (this.overlayRef) {
      this.overlayRef.detach();
    }
  }

better yet, is there something for overlay similar to

<button mat-dialog-close>close</button>

instead of

<button (click)="close()">close</button>
Hileman answered 18/9, 2019 at 3:11 Comment(2)
you could check the dialog source for more insight but I think you are doing it ok. github.com/angular/components/tree/master/src/material/dialogSupranatural
thanks, looks like they use detachBackdrop() which i don't need, and then dispose() which perhaps i should use instead of detach() I'll leave the question here in case in future there is a better way more similar to MatDialogRef<T> and MatBottomSheetRef<T>Hileman
B
12

You can use @Ouput event emitter to emit event from component and then subscribing it in service.

Component Code:

export class ErrorsListBottomSheetComponent implements OnInit {
  @Output() closePanel = new EventEmitter<void>();

  ...

  close() {
    this.closePanel.emit();
  }
}

Service code:

display() {
   ...
   this.ref = overlayRef.attach<ErrorsListBottomSheetComponent>(portal);
   this.ref.instance.closePanel.subscribe(() => overlayRef.detach());
}

Html Code:

<button (click)="close()">Close</button>
Bohner answered 10/3, 2020 at 18:33 Comment(1)
This is the way made my app work. It is actually 2 components communicate between each other. Emitter is definitely a feasible way.Prog
P
3

Yes, there is a nicer way of doing this by providing the injector in the ComponentPortal constructor and then just injecting the OverlayRef in the component directly.

const injector = Injector.create({
  providers: [{ provide: COMPONENT_OVERLAY_REF, useValue: overlayRef }],
});
const userProfilePortal = new ComponentPortal(FooComponent, undefined, injector);

After injector is defined and passed to ComponentPortal we can just inject OverlayRef normally in FooComponent:

constructor(@Inject(COMPONENT_OVERLAY_REF) private overlayRef: OverlayRef) {}

Injection token is defined like so:

export const COMPONENT_OVERLAY_REF = new InjectionToken('COMPONENT_OVERLAY_REF');

You could even provide the OverlayRef directly without using custom MOBILE_MENU_OVERLAY_REF InjectionToken, but I would advise against that as it could lead to some problems and confusion when component is used directly, without CDK overlay.

Perspicacity answered 1/6, 2022 at 15:41 Comment(0)
U
1

Try like this

constructor(private _bottomSheetRef: MatBottomSheetRef<?>, private _bottomSheet: MatBottomSheet) {
}

close() {
  this._bottomSheet.dismiss()
}

// Here MatBottomSheetRef<?> ? is your component
Udder answered 18/9, 2019 at 9:13 Comment(1)
thanks but I don't think this would work because i'm using an overlay rather than a bottomSheet :)Hileman

© 2022 - 2024 — McMap. All rights reserved.