Pass Data Between Web Parts (Connected Web Parts) Using SPFx

Overview

 
This solution contains two web parts where we are passing the data between them by changing the data into one web part that will reflect the change into the other web part. They are the connected web parts.
 

Implementation

  • Create the directory with the name ‘Connected Web parts’.
  • Create the solution by running Yeoxman generator using the below command. 

    Pass Data Between Web Parts (Connected Web Parts) Using SPFx

  • The generator will ask the below information about the new SPFx solution.

    Pass Data Between Web Parts (Connected Web Parts) Using SPFx

  • Yeoman generator will scaffold the process to add the node packages to the existing SPFx solution. Once it is  added to the solution, it will be shown with the below message.

    Pass Data Between Web Parts (Connected Web Parts) Using SPFx

  • Create another web part, which will receive the data from the Source connected web part.
  • To create the new web part into the existing solution, run the below command.

    Pass Data Between Web Parts (Connected Web Parts) Using SPFx

  • It will ask which type of component to create. We will use the ‘WebPart’ component in our case as shown below with providing the below information about the new web part.

    Pass Data Between Web Parts (Connected Web Parts) Using SPFx

  • Once the web part is created, open the solution code in the code editor (like Visual Studio Code) using the below command.

    Pass Data Between Web Parts (Connected Web Parts) Using SPFx

NPM Packages

 
Run the below command to add the packages into the solution.
  1. npm install rx-lite --save  
  2. npm install @types/rx-lite --save  

Update the Solution

 
Create the separate state files (‘IDataSenderWpState.ts’ and ‘IDataReceiverWpState.ts’) for both the web parts. 
 
Create the new folder ‘RxJsEventEmitter’ inside the ‘webparts’ folder and create the ‘IEventData.ts’ and ‘RxJsEventEmitter.ts’ in the ‘RxJsEventEmitter’ folder.
 
The code structure for the current solution will be as below,
 
Pass Data Between Web Parts (Connected Web Parts) Using SPFx
 
Open the ‘IDataSenderWpState.ts’ and define the state object as shown below.
  1. export interface IDataSenderWpState {  
  2.     userName: string;  
  3.     password:string;  
  4. }   
Open the ‘IDataReceiverWpState.ts’ and define the state object as shown below.
  1. export interface IDataReceiverWpState {  
  2.     userName: string;  
  3.     password:string;  
  4. }  
Open ‘IEventData.ts’ and copy the below code.
  1. export interface IEventData {  
  2.     sharedUserName: string;  
  3.     sharedUserPassword:string;  
  4.     
  5. export default IEventData;  
Open ‘RxJsEventEmitter.ts’ and copy the below code.
  1. import { Subject } from "rx-lite";  
  2. import IEventData from "./IEventData";  
  3.   
  4. export class RxJsEventEmitter {  
  5.     public subjects: Object;  
  6.   
  7.     private constructor() {  
  8.         this.subjects = {};  
  9.     }  
  10.   
  11.     public static getInstance(): RxJsEventEmitter   
  12.     {  
  13.         if (!window["RxJsEventEmitter"]) {  
  14.             window["RxJsEventEmitter"] = new RxJsEventEmitter();  
  15.         }  
  16.         return window["RxJsEventEmitter"];  
  17.     }  
  18.   
  19.     public emit(name: string, data: IEventData): void   
  20.     {  
  21.         if (!this.subjects[name]) {  
  22.             this.subjects[name] = new Subject();  
  23.         }  
  24.   
  25.         this.subjects[name].onNext(data);  
  26.     }  
  27.   
  28.     public on(name: string, handler: any): void   
  29.     {  
  30.         if (!this.subjects[name]) {  
  31.             this.subjects[name] = new Subject();  
  32.         }  
  33.   
  34.         this.subjects[name].subscribe(handler);  
  35.     }  
  36. }  
Open the 'DataSenderWp.tsx' file and add the below imports.
  1. import { IDataSenderWpState } from './IDataSenderWpState';  
  2. import IEventData from '../../RxJsEventEmitter/IEventData';  
  3. import { RxJsEventEmitter } from '../../RxJsEventEmitter/RxJsEventEmitter';  
Update the render method and add the other functions. The code for the 'DataSenderWp.tsx' is as below. On change of the UserName or password text field value update, it will pass the data into the other web part using the 'SendData' method. Also, define the object of 'RxJsEventEmitter' inside the class. 
  1. import * as React from 'react';  
  2. import styles from './DataSenderWp.module.scss';  
  3. import { IDataSenderWpProps } from './IDataSenderWpProps';  
  4.   
  5. import { escape } from '@microsoft/sp-lodash-subset';  
  6.   
  7. import { IDataSenderWpState } from './IDataSenderWpState';  
  8. import IEventData from '../../RxJsEventEmitter/IEventData';  
  9. import { RxJsEventEmitter } from '../../RxJsEventEmitter/RxJsEventEmitter';  
  10.   
  11. export default class DataSenderWp extends React.Component<IDataSenderWpProps, IDataSenderWpState> {  
  12.   
  13.   private readonly eventEmitter: RxJsEventEmitter = RxJsEventEmitter.getInstance();  
  14.   
  15.   public constructor(props:IDataSenderWpProps, state:IDataSenderWpState){  
  16.     super(props);  
  17.     this.state = {  
  18.       userName: "",  
  19.       password : ""  
  20.     };  
  21.   }  
  22.   
  23.   public render(): React.ReactElement<IDataSenderWpProps> {  
  24.     return (  
  25.       <div className={styles.dataSenderWp}>  
  26.         <h2>Sender Web Part</h2>  
  27.         <div>User Name:</div>  
  28.         <div>  
  29.           <input type="text" value={this.state.userName} onChange={this._onChangeUserName.bind(this)} />  
  30.         </div>  
  31.         <div>Password:</div>  
  32.         <div>  
  33.           <input type="text" value={this.state.password} onChange={this._onChangePassword.bind(this)} />  
  34.         </div>  
  35.       </div>  
  36.     );  
  37.   }  
  38.   
  39.   private _onChangeUserName(event: any)  
  40.   {  
  41.     this.setState({  
  42.       userName : event.target.value  
  43.     });  
  44.     this.sendData(event.target.value, this.state.password);  
  45.   }  
  46.   
  47.   private _onChangePassword(event: any)  
  48.   {  
  49.     this.setState({  
  50.       password : event.target.value  
  51.     });  
  52.     this.sendData(this.state.userName, event.target.value);  
  53.   }  
  54.   
  55.   private sendData(userName:string, password:string): void   
  56.   {  
  57.     var eventBody = {  
  58.       sharedUserName: userName,  
  59.       sharedUserPassword:password  
  60.     } as IEventData;  
  61.   
  62.     this.eventEmitter.emit("shareData", eventBody);  
  63.   }  
  64. }  
Update 'DataSenderWp.module.scss' file as below.
  1. @import '~office-ui-fabric-react/dist/sass/References.scss';  
  2.   
  3. .dataSenderWp {  
  4.   .container {  
  5.     max-width: 700px;  
  6.     margin: 0px auto;  
  7.     box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.2), 0 25px 50px 0 rgba(0, 0, 0, 0.1);  
  8.   }  
  9.   
  10.   h2{  
  11.     background-color: blue;  
  12.     color:white;  
  13.     padding: 10px 5px;  
  14.   }  
  15.   
  16.   .row {  
  17.     @include ms-Grid-row;  
  18.     @include ms-fontColor-white;  
  19.     background-color: $ms-color-themeDark;  
  20.     padding: 20px;  
  21.   }  
  22.   
  23.   .column {  
  24.     @include ms-Grid-col;  
  25.     @include ms-lg10;  
  26.     @include ms-xl8;  
  27.     @include ms-xlPush2;  
  28.     @include ms-lgPush1;  
  29.   }  
  30.   
  31.   .title {  
  32.     @include ms-font-xl;  
  33.     @include ms-fontColor-white;  
  34.   }  
  35.   
  36.   .subTitle {  
  37.     @include ms-font-l;  
  38.     @include ms-fontColor-white;  
  39.   }  
  40.   
  41.   .description {  
  42.     @include ms-font-l;  
  43.     @include ms-fontColor-white;  
  44.   }  
  45.   
  46.   .button {  
  47.     // Our button  
  48.     text-decoration: none;  
  49.     height: 32px;  
  50.   
  51.     // Primary Button  
  52.     min-width: 80px;  
  53.     background-color: $ms-color-themePrimary;  
  54.     border-color: $ms-color-themePrimary;  
  55.     color: $ms-color-white;  
  56.   
  57.     // Basic Button  
  58.     outline: transparent;  
  59.     position: relative;  
  60.     font-family: "Segoe UI WestEuropean","Segoe UI",-apple-system,BlinkMacSystemFont,Roboto,"Helvetica Neue",sans-serif;  
  61.     -webkit-font-smoothing: antialiased;  
  62.     font-size: $ms-font-size-m;  
  63.     font-weight: $ms-font-weight-regular;  
  64.     border-width: 0;  
  65.     text-align: center;  
  66.     cursor: pointer;  
  67.     display: inline-block;  
  68.     padding: 0 16px;  
  69.   
  70.     .label {  
  71.       font-weight: $ms-font-weight-semibold;  
  72.       font-size: $ms-font-size-m;  
  73.       height: 32px;  
  74.       line-height: 32px;  
  75.       margin: 0 4px;  
  76.       vertical-align: top;  
  77.       display: inline-block;  
  78.     }  
  79.   }  
  80. }  
Open the 'DataReceiverWp.tsx' file and add the below imports.
  1. import { IDataReceiverWpState } from './IDataReceiverWpState';  
  2. import IEventData from '../../RxJsEventEmitter/IEventData';  
  3. import {RxJsEventEmitter} from '../../RxJsEventEmitter/RxJsEventEmitter';   
Update the Render method and add the constructor which calls the function 'receiveData' to get the data from the Sender web part. The entire code for this file is as below.
  1. import * as React from 'react';  
  2. import styles from './DataReceiverWp.module.scss';  
  3. import { IDataReceiverWpProps } from './IDataReceiverWpProps';  
  4. import { escape } from '@microsoft/sp-lodash-subset';  
  5.   
  6. import { IDataReceiverWpState } from './IDataReceiverWpState';  
  7. import IEventData from '../../RxJsEventEmitter/IEventData';  
  8. import {RxJsEventEmitter} from '../../RxJsEventEmitter/RxJsEventEmitter';  
  9.   
  10. export default class DataReceiverWp extends React.Component<IDataReceiverWpProps, IDataReceiverWpState>   
  11. {  
  12.   private readonly eventEmitter: RxJsEventEmitter = RxJsEventEmitter.getInstance();  
  13.   
  14.   public constructor(props:IDataReceiverWpProps, state:IDataReceiverWpState){  
  15.     super(props);  
  16.     this.state = {  
  17.       userName:"",  
  18.       password:""  
  19.     };  
  20.   
  21.     this.eventEmitter.on("shareData"this.receiveData.bind(this));  
  22.   }  
  23.   
  24.   public render(): React.ReactElement<IDataReceiverWpProps> {  
  25.     return (  
  26.       <div className={styles.dataReceiverWp}>  
  27.         <h2>Receiver web part</h2>  
  28.         <div><span>User Name: </span><span>{this.state.userName}</span></div>  
  29.         <div><span>Password: </span><span>{this.state.password}</span></div>  
  30.       </div>  
  31.     );  
  32.   }  
  33.   
  34.   private receiveData(data: IEventData) {  
  35.     this.setState({  
  36.       userName: data.sharedUserName,  
  37.       password:data.sharedUserPassword  
  38.     });  
  39.   }  
  40. }  
Update 'DataSenderWp.module.scss' file as below.
  1. @import '~office-ui-fabric-react/dist/sass/References.scss';    
  2.     
  3. .dataReceiverWp     
  4. {    
  5.   h2{    
  6.     background-color: blue;    
  7.     color:white;    
  8.     padding: 10px 5px;    
  9.   }    
  10.     
  11.   .container {    
  12.     max-width: 700px;    
  13.     margin: 0px auto;    
  14.     box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.2), 0 25px 50px 0 rgba(0, 0, 0, 0.1);    
  15.   }    
  16.     
  17.   .row {    
  18.     @include ms-Grid-row;    
  19.     @include ms-fontColor-white;    
  20.     background-color: $ms-color-themeDark;    
  21.     padding: 20px;    
  22.   }    
  23.     
  24.   .column {    
  25.     @include ms-Grid-col;    
  26.     @include ms-lg10;    
  27.     @include ms-xl8;    
  28.     @include ms-xlPush2;    
  29.     @include ms-lgPush1;    
  30.   }    
  31.     
  32.   .title {    
  33.     @include ms-font-xl;    
  34.     @include ms-fontColor-white;    
  35.   }    
  36.     
  37.   .subTitle {    
  38.     @include ms-font-l;    
  39.     @include ms-fontColor-white;    
  40.   }    
  41.     
  42.   .description {    
  43.     @include ms-font-l;    
  44.     @include ms-fontColor-white;    
  45.   }    
  46.     
  47.   .button {    
  48.     // Our button    
  49.     text-decoration: none;    
  50.     height: 32px;    
  51.     
  52.     // Primary Button    
  53.     min-width: 80px;    
  54.     background-color: $ms-color-themePrimary;    
  55.     border-color: $ms-color-themePrimary;    
  56.     color: $ms-color-white;    
  57.     
  58.     // Basic Button    
  59.     outline: transparent;    
  60.     position: relative;    
  61.     font-family: "Segoe UI WestEuropean","Segoe UI",-apple-system,BlinkMacSystemFont,Roboto,"Helvetica Neue",sans-serif;    
  62.     -webkit-font-smoothing: antialiased;    
  63.     font-size: $ms-font-size-m;    
  64.     font-weight: $ms-font-weight-regular;    
  65.     border-width: 0;    
  66.     text-align: center;    
  67.     cursor: pointer;    
  68.     display: inline-block;    
  69.     padding: 0 16px;    
  70.     
  71.     .label {    
  72.       font-weight: $ms-font-weight-semibold;    
  73.       font-size: $ms-font-size-m;    
  74.       height: 32px;    
  75.       line-height: 32px;    
  76.       margin: 0 4px;    
  77.       vertical-align: top;    
  78.       display: inline-block;    
  79.     }    
  80.   }    
  81. }     
Once all the changes in the file have been done, run the 'gulp serve' command to see the output into the Workbench.aspx page. It will have the below output  for updating into the sender web part for the 'username' or 'password' controls, it will reflect the values into the receiver web part.
 
Pass Data Between Web Parts (Connected Web Parts) Using SPFx
 
Code
 
The code can be found here.