Skip to content

Popup modals sidepanels

Corentin edited this page Sep 3, 2019 · 4 revisions

tl;dr

Overview of the notions used in services LuModal, LuPopup and LuSidepanel, so you can have a better understanding of how it was coded and how it is meant to be used

@Component(/* ... */)
export class MyComponent {
  constructor(private _modal: LuModal) {}
  openModal(data) {
    this._modal.open(MyModal, data, config).onClose
    .subscribe(result => /* ... */);
  }
}

see some examples on prisme

Basics

For popup, modal or sidepanel, the signature of the open method is as follow

open<C, D, R>(component: ComponentType<C>, data?: D, config?): ILuPopupRef<C, D, R>

and the ILuPopupRef interface has this definition:

export interface ILuPopupRef<T, D = any, R = any> {
	onOpen: Observable<D>;
	onClose: Observable<R>;
	open(data: D): void;
	close(result: R): void;
}

so the most basic-est way to use a modal is to write

const ref = this._modal.open(Component, data);
ref.onClose.subscribe(result => ...);

and treat it as you would treat an async call through a service

const call = this._service.call(...args);
call.subscribe(result => ...);

except instead of waiting for a http.get, here you are waiting for the end user to do stuff in the modal.

If you look at how Dialogs are handled in angular material, the data you can transmit to the dialog is a member of the config, here it is a main argument of the method, allowing you to open modals with the same config but not the same data.

Popup/modal/sidepanel - whats different ?

they all do basically the same thing and the way the method open handles is basically the same. But while a popup has no opinions and no restriction on how to use it, a modal or a sidepanel come with some.

You can use the LuPopup as you would use MatDialog, there are no contraints on what component you can open in a popup

A modal, as defined by our UX team, has a title, a cross icon ton left and a footer with 2 actions. one primary, one to dismiss the modal. It is primarily used for handling async actions that could fail and as such the primary button must convey when the action is pending and if it successes or fails.

as a result if you want to open a modal, the component you inject must implement ILuModalContent whose interface definition is

export interface ILuModalContent<T = any> extends ILuPopupContent {
	title: string; // the title for the modal
	submitAction?: () => Observable<T>; // the method that will be called when clicking the primary button
	submitDisabled?: boolean;
	submitLabel?: string; // label of the primary button - default `Ok`
	cancelLabel?: string; // label of the dismiss button - default `Cancel|Annuler`
}

by just providing the primary action, it allows the modal to have a unified user experience

  • while the action is performing, the primary button has the state is-loading
  • if the action succeeds, then the state is-success is applied .5s, before closing the modal
  • if the action throws, then the button becomes is-error 2s before returning to norymal, and the error is displayed in the footer

see prisme for more infos about button states

for now a sidepanel is the same as a modal, but on the side. so the same restrictions apply

To harmonize the user experience in modals, you should use the LuModal service as much as possible. It is a bit restrictive but thats a trade off for the added Comportment.

The LuPopup lets you do whatever you want, but you'll have to implement the same comportment if you want an harmonious UX

Clone this wiki locally