Make your Material MdDialog
stateless by passing data as part of the MdDialogConfig
object.
[Update April 11, 2017]
With the release of @angular/material version 2.0.0-beta.3 the config property of MdDialogRef
has been removed.
We now use the MD_DIALOG_DATA
token to inject the data into our dialog’s component.
See this GitHub issue.
Stateless
What do I mean by stateless? Let’s look at the definition of stateless from Wikipedia:
Of a system or protocol, such that it does not keep a persistent state between transactions.
In a basic sense, a component in our Angular application is considered stateful when it:
- is dependent on requesting data from a service,
- has knowledge about the state of the application,
- resolves data via routing, or
- changes the state of our application.
And, a component might be considered stateless when it:
- receives data via input properties,
- does not request data from a service,
- emits data to a parent stateful component that acts upon it, or
- renders further stateless components.
Stateless components are sometimes referred to as dumb components.
Want to read more about stateless vs. stateful components? Check out Todd Motto’s article on Stateful and Stateless components.
Passing data in MdDialogConfig
First, let’s take a look at the MdDialogConfig
interface:
/**
* Configuration for opening a modal dialog with the MdDialog service.
*/
export declare class MdDialogConfig {
viewContainerRef?: ViewContainerRef;
/** The ARIA role of the dialog element. */
role?: DialogRole;
/** Whether the user can use escape or clicking outside to close a modal. */
disableClose?: boolean;
/** Width of the dialog. */
width?: string;
/** Height of the dialog. */
height?: string;
/** Position overrides. */
position?: DialogPosition;
/** Data being injected into the child component. */
data?: any;
}
Note the data
property. It allows us to inject data into the child component that is created when we open()
an MdDialog
.
Here is an example component that opens the dialog and passes a User
model object to the child component:
import { Component, Input } from "@angular/core";
import { MdDialog } from "@angular/material";
//dialog
import { InviteDialogComponent } from "../dialogs/invite-dialog/invite-dialog.component";
//model
import { User } from "../models/user";
/**
* The invite card.
* @class InviteCardComponent
*/
@Component({
selector: "j11-invite-card",
templateUrl: "./invite-card.component.html",
styleUrls: ["./invite-card.component.scss"]
})
export class InviteCardComponent {
//the authenticated user
@Input() public user: User;
/**
* @constructor
* @param {MdDialog} mdDialog
*/
constructor(private mdDialog: MdDialog) { }
/**
* Open the dialog to send an invite
* @method openInviteDialog
*/
public openInviteDialog() {
this.mdDialog.open(InviteDialogComponent, {
disableClose: true,
data: {
user: this.user
}
});
}
}
Let’s review the InviteCardComponent
:
- We import
MdDialog
from the@angular/material
package. - This component itself is stateless and receives the
user
via property binding. - We inject an instance of
MdDialog
in theconstructor
function. - The
openInviteDialog()
method is invoked by the UI to open theInviteDialogComponent
dialog. - The
data
property is an object that contains our custom data that will be passed to the child dialog component.
Accessing custom Data
First, we need to import the MD_DIALOG_DATA
constant, which is really just an instance of the OpaqueToken
class:
import { MdDialogRef, MD_DIALOG_DATA } from '@angular/material';
Next, use the @Inject()
decorator to inject the data via our constructor()
function:
constructor(@Inject(MD_DIALOG_DATA) private data: { user: User })
Now we just pick that data up inside our child component’s ngOnInit()
method.
Here is the full example:
import { Component, Inject, OnInit } from "@angular/core";
import { MdDialogRef, MD_DIALOG_DATA } from "@angular/material";
//model
import { User } from "../models/user";
@Component({
selector: "j11-invite-dialog",
templateUrl: "./invite-dialog.component.html",
styleUrls: ["./invite-dialog.component.scss"]
})
export class InviteDialogComponent implements OnInit {
//authenticated user
public user: User;
/**
* @constructor
* @param {Object} data
* @param {MdDialogRef<InviteDialogComponent>} mdDialogRef
*/
constructor(
@Inject(MD_DIALOG_DATA) private data: { user: User },
private mdDialogRef: MdDialogRef<InviteDialogComponent>
) { }
/**
* Let's do this.
* @method ngOnInit
*/
public ngOnInit() {
//set custom data from parent component
this.user = this.data.user;
}
}
OK, let’s review the code above:
- First, I am importing the
Inject
decorator. - Then, I am importing the
MdDialogRef
class and theMD_DIALOG_DATA
constant. - I have declared a publicly accessible variable named
user
that is the authenticated user in my app. - The
data
is injected in theconstructor
function using the@Inject
decorator. - Finally, in the
ngOnInit()
method I am setting the reference ofuser
.
That’s it. Super easy. Thanks to the @angular/material2 team!