How To Use Dialog Control Of Fluent UI In SPFx

Introduction

 
A dialog box (Dialog) is a temporary pop-up that takes the focus from the page or app and requires people to interact with it. It’s primarily used for confirming actions, such as deleting a file or asking people to make a choice.
 
For more details refer to this article.
 
 
So, in this article, we will see step-by-step implementation with SPFx webpart.
 

Scenario

 
In this example, we will show list data in the table format. In the table, we will show only 4 columns with the data and for more details, we are creating a link and with the click of a link, we will open a dialog box with all details.
 
In the end, our output will be like this:
 
Output
 
Implementation
  • Open a command prompt
  • Move to the path where you want to create a project
  • Create a project directory using:
  1. md spfx-fluentui-dialog  
Move to the above-created directory using:
  1. cd spfx-fluentui-dialog  
Now execute the below command to create an SPFx solution:
  1. yo @microsoft/sharepoint  
It will ask some questions, as shown below,
 
Project Setup
 
After a successful installation, we can open a project in any source code tool. Here, I am using the VS code, so I will execute the command:
  1. code .  
Now we will install pnpjs as shown below:
  1. npm install @pnp/sp --save  
Now go to the src > webparts > webpart > components > I{webpartname}Props.ts file,
 
Here we will pass the list name from the property pane configuration. 
  1. import { WebPartContext } from "@microsoft/sp-webpart-base";  
  2.   
  3. export interface ISpfxUifabricDialogProps {  
  4.   description: string;  
  5.   listName: string;  
  6.   context: WebPartContext;  
  7. }  
Create a file I{webpartname}State.ts inside src > webparts > webpart > components and create a state interface as below,
  1. export interface ISpfxUifabricDialogState {  
  2.   dialogItems: any[];  
  3.   selectedItem: any;  
  4.   openDialog: boolean;  
  5. }  
Create a Service folder inside the src folder and then in this folder create a file called SPService.ts. And in this file, we will create a service to get list items as below,
 
Here list name comes from property pane configuration.
  1. import { WebPartContext } from "@microsoft/sp-webpart-base";  
  2. import { sp } from "@pnp/sp/presets/all";  
  3.   
  4. export class SPService {  
  5.   
  6.     public constructor(spcontext: WebPartContext) {  
  7.         sp.setup({  
  8.             spfxContext: spcontext  
  9.         });  
  10.     }  
  11.   
  12.     public getDialogListItems(litsName: string) {  
  13.         let items = sp.web.lists.getByTitle(litsName)  
  14.             .items  
  15.             .select("Title,ReasonForTravel,Destination,TravelStartDate,TravelEndDate,Airline,EstimatedAirfare,Hotel,EstimatedHotelCost,Approved,Requester/Title")  
  16.             .expand("Requester")  
  17.             .get();  
  18.         return items;  
  19.     }  
  20. }  
Create a folder called Dialog inside src> common > components. And inside Dialog folder create a files DetailsDialog.tsx and DetailsDialog.module.scss.
 
In the DetailsDialog.tsx file, we will create a common dialog component so we can reuse it in our spfx web part. 
 
Create below properties:
  • item - we will pass from the parent component,
  • open - to open a dialog,
  • onClose() - method to close the dialog.
Create a const dialogDetails, in this, will set the label to display in the dialog, and in the value, we will pass the list columns internal name and it comes from an item object.
Create a const dialogContentProps. In this, we have to set dialog type and dialog title.
 
In the render() method we will render a dialog box with details.
  1. import * as React from 'react';  
  2. import { Dialog, DialogFooter, DialogType } from 'office-ui-fabric-react/lib/Dialog';  
  3. import { useBoolean } from '@uifabric/react-hooks';  
  4. import { DefaultButton, PrimaryButton } from 'office-ui-fabric-react/lib/Button';  
  5. import styles from './DetailsDialog.module.scss';  
  6.   
  7. export interface DetailsDialogProps {  
  8.   children?: never[]  
  9.   item: any;  
  10.   open: boolean;  
  11.   onClose: () => void  
  12. }  
  13.   
  14. export function DetailsDialog(props: DetailsDialogProps) {  
  15.   
  16.   function formatValue(val: string) {  
  17.     return (val ? val : "-");  
  18.   }  
  19.   
  20.   const { open, onClose, item } = props;  
  21.   
  22.   const dialogStyles = { main: { maxWidth: 800 } };  
  23.   
  24.   const dialogDetails = [  
  25.     { label: "Reason For Travel", value: formatValue(item.ReasonForTravel) },  
  26.     { label: "Destination", value: formatValue(item.Destination.DisplayName) },  
  27.     { label: "Travel Star tDate", value: formatValue(item.TravelStartDate) },  
  28.     { label: "Travel End Date", value: formatValue(item.TravelEndDate) },  
  29.     { label: "Airline", value: formatValue(item.Airline) },  
  30.     { label: "Estimated Airfare", value: formatValue(item.EstimatedAirfare) },  
  31.     { label: "Hotel", value: formatValue(item.Hotel.DisplayName) },  
  32.     { label: "Approved", value: formatValue(item.Approved) },  
  33.     { label: "Requester", value: formatValue(item.Requester.Title) }  
  34.   ]  
  35.   
  36.   const dialogContentProps = {  
  37.     type: DialogType.normal,  
  38.     title: 'Item Details',  
  39.   };  
  40.   
  41.   const handleClose = () => () => {  
  42.     onClose();  
  43.   };  
  44.   
  45.   const modalProps = {  
  46.     isBlocking: true,  
  47.   }  
  48.   
  49.   return (  
  50.     <Dialog  
  51.       hidden={!open}  
  52.       onDismiss={handleClose()}  
  53.       dialogContentProps={dialogContentProps}  
  54.       styles={dialogStyles}  
  55.       modalProps={modalProps}>  
  56.   
  57.       <div className={styles.detailsGrid}>  
  58.         {  
  59.           dialogDetails.map(d =>  
  60.             <>  
  61.               <div>  
  62.                 <strong>{d.label}</strong>  
  63.               </div>  
  64.               <div>{d.value}</div>  
  65.             </>)  
  66.         }  
  67.       </div>  
  68.       <DialogFooter>  
  69.         <DefaultButton onClick={handleClose()} text="Cancel" />  
  70.       </DialogFooter>  
  71.     </Dialog>  
  72.   );  
  73. }  
DetailsDialog.module.scss 
  1. .detailsGrid {  
  2.     display: grid;  
  3.     grid-template-columns: 50% 70%;  
  4. }  
Now move to the {webpartname}Webpart.ts and create a listname property in property pane configuration and pass a context and selected list property as below:
  1. import * as React from 'react';  
  2. import * as ReactDom from 'react-dom';  
  3. import { Version } from '@microsoft/sp-core-library';  
  4. import {  
  5.   IPropertyPaneConfiguration,  
  6.   PropertyPaneTextField  
  7. } from '@microsoft/sp-property-pane';  
  8. import { BaseClientSideWebPart } from '@microsoft/sp-webpart-base';  
  9.   
  10. import * as strings from 'SpfxUifabricDialogWebPartStrings';  
  11. import SpfxUifabricDialog from './components/SpfxUifabricDialog';  
  12. import { ISpfxUifabricDialogProps } from './components/ISpfxUifabricDialogProps';  
  13.   
  14. export interface ISpfxUifabricDialogWebPartProps {  
  15.   listName: string;  
  16.   description: string;  
  17. }  
  18.   
  19. export default class SpfxUifabricDialogWebPart extends BaseClientSideWebPart<ISpfxUifabricDialogWebPartProps> {  
  20.   
  21.   public render(): void {  
  22.     const element: React.ReactElement<ISpfxUifabricDialogProps> = React.createElement(  
  23.       SpfxUifabricDialog,  
  24.       {  
  25.         description: this.properties.description,  
  26.         listName: this.properties.listName,  
  27.         context: this.context,  
  28.       }  
  29.     );  
  30.   
  31.     ReactDom.render(element, this.domElement);  
  32.   }  
  33.   
  34.   protected onDispose(): void {  
  35.     ReactDom.unmountComponentAtNode(this.domElement);  
  36.   }  
  37.   
  38.   protected get dataVersion(): Version {  
  39.     return Version.parse('1.0');  
  40.   }  
  41.   
  42.   protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration {  
  43.     return {  
  44.       pages: [  
  45.         {  
  46.           header: {  
  47.             description: strings.PropertyPaneDescription  
  48.           },  
  49.           groups: [  
  50.             {  
  51.               groupName: strings.BasicGroupName,  
  52.               groupFields: [  
  53.                 PropertyPaneTextField('description', {  
  54.                   label: strings.DescriptionFieldLabel  
  55.                 }),  
  56.                 PropertyPaneTextField('listName', {  
  57.                   label: strings.ListNameFieldLabel  
  58.                 })  
  59.               ]  
  60.             }  
  61.           ]  
  62.         }  
  63.       ]  
  64.     };  
  65.   }  
  66. }  
Move to the {webpartname}.tsx file and then bind the service using current context and call service to get the list items and set values in the state and render it in a table format and on the click of particular items we will show all the item details in the dialog box as shown below:
  • Import all the required components like state, dialog component, etc. 
  • Create a constructor to bind service and initialize states.
  • Create a method getDialogItems() and set items in a state.
  • Create a method componentDidMount() and componentDidUpdate() to call getDialogItems().
  • Create a method openDialog() to open a dialog for a selected item.
  • Create a method closeDialog() to close the dialog.
Render the data by states.
  1. import * as React from 'react';  
  2. import styles from './SpfxUifabricDialog.module.scss';  
  3. import { ISpfxUifabricDialogProps } from './ISpfxUifabricDialogProps';  
  4. import { ISpfxUifabricDialogState } from './ISpfxUifabricDialogState';  
  5. import { escape } from '@microsoft/sp-lodash-subset';  
  6. import { SPService } from '../../../common/Services/SPService';  
  7. import { DetailsDialog } from '../../../common/Components/Dialog/DetailsDialog';  
  8. import { Label } from 'office-ui-fabric-react';  
  9.   
  10. export default class SpfxUifabricDialog extends React.Component<ISpfxUifabricDialogProps, ISpfxUifabricDialogState> {  
  11.   
  12.   private _spService: SPService;  
  13.   
  14.   constructor(props: ISpfxUifabricDialogProps) {  
  15.     super(props);  
  16.     this.state = {  
  17.       dialogItems: [],  
  18.       openDialog: false,  
  19.       selectedItem: {}  
  20.     }  
  21.     this._spService = new SPService(this.props.context);  
  22.   }  
  23.   
  24.   public openDialog(item) {  
  25.     return function () {  
  26.       this.setState({ selectedItem: item, openDialog: true });  
  27.     }  
  28.   }  
  29.   
  30.   public closeDialog() {  
  31.     this.setState({ openDialog: false })  
  32.   }  
  33.   
  34.   public async getDialogItems() {  
  35.     let { listName } = this.props;  
  36.     if (listName) {  
  37.       let items = await this._spService.getDialogListItems(listName);  
  38.       this.setState({ dialogItems: items });  
  39.     }  
  40.   }  
  41.   
  42.   public componentDidMount() {  
  43.     this.getDialogItems();  
  44.   }  
  45.   
  46.   public componentDidUpdate(prevProps: ISpfxUifabricDialogProps) {  
  47.     if (prevProps.listName !== this.props.listName) {  
  48.       this.getDialogItems();  
  49.     }  
  50.   }  
  51.   
  52.   public render(): React.ReactElement<ISpfxUifabricDialogProps> {  
  53.     return (  
  54.       <div>  
  55.         {  
  56.           this.state.dialogItems.length ?  
  57.             <div className={styles.spfxUifabricDialog}>  
  58.               <div>  
  59.                 <strong>{this.props.description ? this.props.description : ''}</strong>  
  60.               </div>  
  61.               <table className={styles.detailsTable}>  
  62.                 <thead>  
  63.                   <th>Title</th>  
  64.                   <th>Travel Start Date</th>  
  65.                   <th>Travel End Date</th>  
  66.                   <th>Reason For Travel</th>  
  67.                   <th>Details</th>  
  68.                 </thead>  
  69.                 <tbody>  
  70.                   {  
  71.                     this.state.dialogItems.map(i => (  
  72.                       <tr>  
  73.                         <td>{i.Title}</td>  
  74.                         <td>{i.TravelStartDate}</td>  
  75.                         <td>{i.TravelEndDate}</td>  
  76.                         <td>{i.ReasonForTravel}</td>  
  77.                         <td><a href="#" onClick={this.openDialog(i).bind(this)}>More Details</a> </td>  
  78.                       </tr>  
  79.                     ))  
  80.                   }  
  81.                 </tbody>  
  82.               </table>  
  83.               {  
  84.                 this.state.openDialog ?  
  85.                   <DetailsDialog  
  86.                     open={this.state.openDialog}  
  87.                     item={this.state.selectedItem}  
  88.                     onClose={this.closeDialog.bind(this)}  
  89.                   >  
  90.                   </DetailsDialog>  
  91.                   : <></>  
  92.               }  
  93.             </div>  
  94.             : <></>  
  95.         }  
  96.       </div>  
  97.     );  
  98.   }  
  99. }  
Output
 
Output - Dialog 
 
Find the full source code here
 

Summary

 
In this article, we have seen how to implement dialog control of fluent UI in the SPFx webpart.
 
I hope this helps.
 
Sharing is caring!