Wednesday, December 23, 2020

CRUD Operation Using SPFx And React JS (SharePoint Online)

In our last post we have discussed on "CRUD Operations Using SPFx (SharePoint Online)". Let us discuss now on "CRUD Operation Using SPFx And React JS (SharePoint Online)".


Now, let us see, how we can create SPFx webpart. Before creating SPFx webpart, there are some pre-requisites that need to fulfill. Please refer SPFx Prerequisites page.

Let's begin-

  1. Open command prompt and move to the folder where you need to create SPFx solution. I am creating SPFx solution in D drive.

  2. Now create a folder where SPFx solution files will be created using command "md CRUDOperationsReactJSSPFx". You make choose any name as per your wish. "md" is the DOS command to create directory/folder.
  3. Change the directory path using command "cd CRUDOperationsReactJSSPFx". "cd" is the DOS command to change the directory/folder.

  4. Execute the command "yo @microsoft/sharepoint". It runs Yeoman SharePoint Generator to create a new SPFx web part. Sometimes, it happens that when we had installed all the pre requisites, it doesn't gets installed globally. In that case, it fails to recognize the command.

  5. In such case, find out the path where all the installations took place. Copy the complete path and paste it before "yo". Press Enter

  6. Now, it will ask a series of questions ( name can be of your choice 😊 ) -
    1. What is your solution name? : CRUDOperationsReactJSSPFxSolution


    2. Which baseline packages do you want to target for your component(s)? : SharePoint Online only (latest)

    3. Where do you want to place the files? : Use the current folder

    4. Do you want to allow the tenant admin the choice of being able to deploy the solution to all sites immediately without running any feature deployment or adding apps in sites? : N


    5. Will the components in the solution require permissions to access web APIs that are unique and not shared with other components in the tenant? : N


    6. Which type of client-side component to create? : WebPart

  7. Apart form it, now it will ask the next set of questions that are specific about your web part ( name/description can be of your choice 😊 ) -
    1. What is your Web part name? : CRUDOperationsReactJSSPFxWP

    2. What is your Web part description? : Manage CRUD Operations Using SPFx And React JS

    3. Which framework would you like to use? : React

  8. Once you press Enter, it will start creating the SPFx webpart. It may take from 2-3 minutes to 20-25 minutes.


  9. Once completed, a Congratulations! message will be displayed on screen.

  10. Finally, WebPart has been created successfully. Now you may view it on local workbench, how it is looking. But we are stopping here as we have to modify it as per our need. Hence we will open the code in Visual Studio Code Editor. For this we will use "code ." command.

  11. Press Enter. It will open the SPFx webpart code is VSC editor.

  12. Coming back to command prompt window, we will use another command to see how the default WebPart looks like. For this we will use "gulp serve" command. In case of path issue, use the complete path

  13. This command executes a series of gulp tasks to create and start a local webserver hosting the endpoints localhost:4321 and localhost:5432. It will then open your default browser and load the workbench preview web parts from your local dev environment.

  14. 😟 Where is my webpart?
  15. Relax! Click on the + sign showing at the middle. It will populate the available webpart.

  16. Here is our webpart. Click on it. It will be added to the local workbench.

  17. Now, open your Sharepoint online site. change the root URL by removing the SitePages/<YourDefaultPage>.aspx by "_layouts/15/workbench.aspx" (https://yoursitename.sharepoint.com/sites/yoursubsitename/_layouts/15/workbench.aspx) and press Enter. (Remember WorkBench is available only in Online Site. It is not available in SharePoint 2016/2013...).

  18. This is your SharePoint site workbench. Now click on + sign at the middle. Surprisingly, It will show your webpart along with others.

  19. Click on it. It will be added to the SharePoint site workbench.

  20. Till now, we were creating our default SPFx webpart. Now we have to modify it so that we can try CRUD operations using it. For this, first we need a SharePoint list. I am using a simple list (name:- Registration Details) with 4 columns-
    1. Title : (or Full Name) of type Single Line of Text
    2. Address : of type Single Line of Text
    3. Mobile : of type Single Line of Text
    4. EmailID : of type Single Line of Text

  21. Fine. Till now you have done good job. Now, come to the code part. Remember, we had opened our SPFx webpart code in code editor using "code ." command.

  22. All the files which we need to create/edit can be accessed through Explorer window-

  23. Now the next process is split into 4 parts-
    1. Configure Property for List Name
    2. Model for List Item
    3. Add Controls to WebPart
    4. Implement CRUD Operations
      1. CREATE
      2. READ
      3. UPDATE
      4. DELETE
  24. Configure Property for List Name
  25. Here we will update below files-
    1. src\webparts\crudOperationsReactJsspFxWp\loc\mystrings.d.ts
    2. src\webparts\crudOperationsReactJsspFxWp\loc\en-us.js
    3. src\webparts\crudOperationsReactJsspFxWp\components\ICrudOperationsReactJsspFxWpProps.ts
    4. src\webparts\crudOperationsReactJsspFxWp\CrudOperationsReactJsspFxWpWebPart.ts
    5. src\webparts\crudOperationsReactJsspFxWp\components\CrudOperationsReactJsspFxWp.tsx
  26. Let's do step by step. Open the file "src\webparts\crudOperationsReactJsspFxWp\loc\mystrings.d.ts" and rename
    1. DescriptionFieldLabel to ListNameFieldLabel
  27. BEFORE-
  28. declare interface ICrudOperationsReactJsspFxWpWebPartStrings {
      PropertyPaneDescriptionstring;
      BasicGroupNamestring;
      DescriptionFieldLabelstring;
    }
  29. AFTER-
  30. declare interface ICrudOperationsReactJsspFxWpWebPartStrings {
      PropertyPaneDescriptionstring;
      BasicGroupNamestring;
      ListNameFieldLabelstring;
    }
  31. Next Open the file "src\webparts\crudOperationsReactJsspFxWp\loc\en-us.js" and rename 
    1. DescriptionFieldLabel to ListNameFieldLabel
    2. "Description Field" to "List Name"
  32. BEFORE-
  33. define([], function() {
      return {
        "PropertyPaneDescription": "Description",
        "BasicGroupName": "Group Name",
        "DescriptionFieldLabel": "Description Field"
      }
    });
  34. AFTER-
  35. define([], function() {
      return {
        "PropertyPaneDescription": "Description",
        "BasicGroupName": "Group Name",
        "ListNameFieldLabel": "List Name"
      }
    });
  36. Next Open the file "src\webparts\crudOperationsReactJsspFxWp\components\ICrudOperationsReactJsspFxWpProps.ts" and rename 
    1. description to listName
  37. BEFORE-
  38. export interface ICrudOperationsReactJsspFxWpProps {
      descriptionstring;
    }
  39. AFTER-
  40. export interface ICrudOperationsReactJsspFxWpProps {
      listNamestring;
    }
  41. Next Open the file "src\webparts\crudOperationsReactJsspFxWp\CrudOperationsReactJsspFxWpWebPart.ts" and rename 
    1. description to listName
    2. DescriptionFieldLabel to ListNameFieldLabel
  42. BEFORE-
  43. export interface ICrudOperationsReactJsspFxWpWebPartProps {
      descriptionstring;
    }
  44. AFTER-
  45. export interface ICrudOperationsReactJsspFxWpWebPartProps {
      listNamestring;
    }
  46. BEFORE-
  47. public render(): void {
        const elementReact.ReactElement<ICrudOperationsReactJsspFxWpProps> = React.createElement(
          CrudOperationsReactJsspFxWp,
          {
            description: this.properties.description
          }
        );

        ReactDom.render(elementthis.domElement);
      }
  48. AFTER-
  49. public render(): void {
        const elementReact.ReactElement<ICrudOperationsReactJsspFxWpProps> = React.createElement(
          CrudOperationsReactJsspFxWp,
          {
            listName: this.properties.listName
          }
        );

        ReactDom.render(elementthis.domElement);
      }
  50. BEFORE-
  51. groups: [
                {
                  groupName: strings.BasicGroupName,
                  groupFields: [
                    PropertyPaneTextField('description', {
                      label: strings.DescriptionFieldLabel
                    })
                  ]
                }
              ]
  52. AFTER-
  53. groups: [
                {
                  groupName: strings.BasicGroupName,
                  groupFields: [
                    PropertyPaneTextField('listName', {
                      label: strings.ListNameFieldLabel
                    })
                  ]
                }
              ]
  54. Now Open last file of this section "src\webparts\crudOperationsReactJsspFxWp\components\CrudOperationsReactJsspFxWp.tsx" and rename
    1. description to listName
  55. BEFORE-
  56. <p className={ styles.description }>{escape(this.props.description)}</p>
  57. AFTER-
  58. <p className={ styles.description }>{escape(this.props.listName)}</p>
  59. Now, if your workbench is still running, refresh the page. You will get the webpart as below-

  60. Now click on webpart. Webpart edit controls will appear on left side. click on pencil icon-

  61. A new property window will appear on right side. Type the list name in the box provided. You will see that as you change the name, the same appears on webpart-

  62. The first part completes. Now we will create some models to pass list item data and the state of process execution. 
  63. Model for List Item
  64.  Here we will create below files-
    1. src\webparts\crudOperationsReactJsspFxWp\components\IListItem.ts
    2. src\webparts\crudOperationsReactJsspFxWp\components\CrudOperationsReactJsspFxWpState.ts
  65. Then we will update below file-
    1. src\webparts\crudOperationsReactJsspFxWp\components\CrudOperationsReactJsspFxWp.tsx
  66. Let's create the IListItem.ts file at path "src\webparts\crudOperationsReactJsspFxWp\components\". For this click on components in Explorer window and type in the file name with extension "IListItem.ts"-


  67. Add code to this file-
  68. export interface IListItem {
        Title:string;
        Address:string;
        Mobile:string;
        EmailID:string;
        ID:Int32Array;
    }
  69. The file will appear like below-

  70. As ReactJS acts on change of state. Hence let's add a state to our solution. For this, create the CrudOperationsReactJsspFxWpState.ts file at path "src\webparts\crudOperationsReactJsspFxWp\components\". For this click on components in Explorer window and type in the file name with extension "CrudOperationsReactJsspFxWpState.ts", the same way we did for "IListItem.ts"-

  71. Import "IListItem" in this file then add an interface as below-
  72. import {IListItemfrom './IListItem'

    export interface ICrudOperationsReactJsspFxWpState{
        status:string;
        items:IListItem[];
    }
  73. The file will appear as below-

  74. Now we will update the "src\webparts\crudOperationsReactJsspFxWp\components\CrudOperationsReactJsspFxWp.tsx" file.
  75. Look for the code-
  76. import { ICrudOperationsReactJsspFxWpProps } from './ICrudOperationsReactJsspFxWpProps';
  77. Now import "CrudOperationsReactJsspFxWpState.ts" file after it-
  78. import {ICrudOperationsReactJsspFxWpStatefrom './CrudOperationsReactJsspFxWpState'
  79. Then look for below code line-
  80. export default class CrudOperationsReactJsspFxWp extends React.Component<ICrudOperationsReactJsspFxWpProps, {}> {
  81. Replace with below-
  82. export default class CrudOperationsReactJsspFxWp extends React.Component<ICrudOperationsReactJsspFxWpPropsICrudOperationsReactJsspFxWpState> {
  83. Now add a constructor after the above line-
  84. constructor (props:ICrudOperationsReactJsspFxWpPropsstate:ICrudOperationsReactJsspFxWpState)
      {
        super(props);
        this.state = {
          status:'Ready',
          items:[]
        };
      }
  85. Now the file looks like below-

  86. This completes the Model Part. Now we will add controls to the webpart so that we can perform CRUD operations-
  87. Add Controls To WebPart  
  88. Here we will update below files-
    1. src\webparts\crudOperationsReactJsspFxWp\components\ICrudOperationsReactJsspFxWpProps.ts
    2. src\webparts\crudOperationsReactJsspFxWp\components\CrudOperationsReactJsspFxWp.tsx
    3. src\webparts\crudOperationsReactJsspFxWp\CrudOperationsReactJsspFxWpWebPart.ts
    4. src\webparts\crudOperationsReactJsspFxWp\components\CrudOperationsReactJsspFxWp.module.scss
  89. Let's start.
  90. Open "ICrudOperationsReactJsspFxWpProps.ts" file at location "src\webparts\crudOperationsReactJsspFxWp\components\".
  91. Add two more properties-
  92. spHttpClientSPHttpClient;
      siteUrlstring;
  93. Also add reference of SPHttpClient-
  94. import {SPHttpClientfrom '@microsoft/sp-http';

  95. BEFORE-

  96. AFTER-

  97. Now open "CrudOperationsReactJsspFxWp.tsx" file at location "src\webparts\crudOperationsReactJsspFxWp\components\"
  98. Look for the below code-
  99. import { escape } from '@microsoft/sp-lodash-subset';

  100. Import "IListItem" interface after it-
  101. import {IListItemfrom './IListItem';
  102. BEFORE-

  103. AFTER-

  104. Now import "SPHttpClient" and "SPHttpClientResponse" after above-
  105. import {SPHttpClientfrom '@microsoft/sp-http';
    import {SPHttpClientResponsefrom '@microsoft/sp-http';

  106. Then add Props interface- 
  107. import { ICrudOperationsReactJsspFxWpWebPartProps } from '../CrudOperationsReactJsspFxWpWebPart';

  108. It will look like-

  109. Now update the render() method-
  110. Look for the code-
  111. public render(): React.ReactElement<ICrudOperationsReactJsspFxWpProps> {
        return (
          <div className={ styles.crudOperationsReactJsspFxWp }>
            <div className={ styles.container }>
              <div className={ styles.row }>
                <div className={ styles.column }>
                  <span className={ styles.title }>Welcome to SharePoint!</span>
                  <p className={ styles.subTitle }>Customize SharePoint experiences using Web Parts.</p>
                  <p className={ styles.description }>{escape(this.props.listName)}</p>
                  <a href="https://aka.ms/spfx" className={ styles.button }>
                    <span className={ styles.label }>Learn more</span>
                  </a>
                </div>
              </div>
            </div>
          </div>
        );
      }
  112. Replace it with below-
  113. public render(): React.ReactElement<ICrudOperationsReactJsspFxWpProps> {
        const tblPrefix = `<table className={styles.table}>
        <th className={styles.th}>Full Name</th>
        <th className={styles.th}>Address</th>
        <th className={styles.th}>Email ID</th>
        <th className={styles.th}>Phone Number</th>
        <th className={styles.th}>Edit</th>
        <th className={styles.th}>Delete</th>`;
        const tblSuffix = `</table>`;
        const itemsCount = this.state.items.length;
        const itemsJSX.Element[] = this.state.items.map((itemIListIteminumber): JSX.Element => {  
          return (  
            <tr className={styles.tr}>
              <td className={styles.td}>{item.ID}</td>
              <td className={styles.td}>{item.Title}</td>
              <td className={styles.td}>{item.Address}</td>
              <td className={styles.td}>{item.EmailID}</td>
              <td className={styles.td}>{item.Mobile}</td>
              <td className={styles.td}><button id="btnGetRecordData" className={styles['getRecord-Button']} data-val={`${item.ID}`} onClick={() => this.UpdateWithGridEditButton(item.ID)}>Edit</button></td>
              <td className={styles.td}><button id="btnDelRecordData" className={styles['delRecord-Button']} data-val={`${item.ID}`} onClick={() => this.DeleteWthGridDeleteButton(item.ID)}>Delete</button></td>
            </tr>  
          );  
        });
        return (
          <div className={ styles.crudOperationsReactJsspFxWp }>
            <div className={ styles.container }>
              <div className={ styles.row }>
                <div className={ styles.column }>
                  <span className={ styles.title }>Welcome to SharePoint!</span>
                  <p className={ styles.subTitle }>Customize SharePoint experiences using Web Parts.</p>
                  <p className={ styles.description }>{escape(this.props.listName)}</p>
                  <div>       
                    <table>  
                      <tr>  
                        <td>Full Name</td>            
                        <td><input type="text" id="idFullName" name="fullName" placeholder="Full Name.."/></td>
                      </tr>          
                      <tr>            
                        <td>Address</td>            
                        <td><input type="text" id="idAddress" name="address" placeholder="Address.."/></td>
                      </tr>          
                      <tr>            
                        <td>Mobile Number</td>            
                        <td><input type="text" id="idPhoneNumber" name="mobile" placeholder="Mobile Number.."/></td>
                      </tr>          
                      <tr>            
                        <td>Email ID</td>            
                        <td><input type="text" id="idEmailId" name="emailid" placeholder="Email ID.."/></td>
                      </tr>
                    </table>    
                    <div id="tblRegistrationDetails"></div>
                  </div>
                  <div className={`ms-Grid-row ms-bgColor-themeDark ms-fontColor-white ${styles.row}`}>  
                    <div className='ms-Grid-col ms-u-lg10 ms-u-xl8 ms-u-xlPush2 ms-u-lgPush1'>  
                      <a href="#" className={`${styles.button}`} onClick={() => this.createItem()}>  
                        <span className={styles.label}>Create</span>  
                      </a>

                      <a href="#" className={`${styles.button}`} onClick={() => this.updateItem()}>  
                        <span className={styles.label}>Update</span>  
                      </a>

                      <a href="#" className={`${styles.button}`} onClick={() => this.deleteItem()}>  
                        <span className={styles.label}>Delete</span>  
                      </a>

                      {/* <a href="#" className={`${styles.button}`} onClick={() => this.readItem()}>  
                        <span className={styles.label}>Read</span>  
                      </a> */}
                    
                      <a href="#" className={`${styles.button}`} onClick={() => this.getListData()}>  
                        <span className={styles.label}>All Data</span>  
                      </a> 
                    </div>  
                  </div>  
      
                  <div className={`ms-Grid-row ms-bgColor-themeDark ms-fontColor-white ${styles.row}`}>  
                    <div className='ms-Grid-col ms-u-lg10 ms-u-xl8 ms-u-xlPush2 ms-u-lgPush1'>  
                      {this.state.status}
                        {
                          this.state.items.length ?
                            <table className={styles.table}>
                            <th className={styles.th}>ID</th>
                            <th className={styles.th}>Full Name</th>
                            <th className={styles.th}>Address</th>
                            <th className={styles.th}>Email ID</th>
                            <th className={styles.th}>Phone Number</th>
                            <th className={styles.th}>Edit</th>
                            <th className={styles.th}>Delete</th>
                            {items}
                          </table>
                          :''
                        }
                    </div>  
                  </div>
                </div>
              </div>
            </div>
          </div>
        );
      }
  114. This piece of code contains-
    1. Input Boxes to capture data to perform CRUD Operations
    2. CRUD operations button
    3. Table structure to show all records on page load
  115. Now add CRUD functions after the above piece of code (means at the end of file just before the last closing bracket "}"-
    1. CREATE
    2. UDPATE
    3. DELETE
    4. READ
    5. UPDATE (With Grid Edit Button)
    6. DELETE (WIth Grid Delete Button)
    7. CLEAR (To Reset The Input Fields)
  116. CREATE-
  117. private createItem(): void {
        this.setState({  
          status: 'Creating item...',  
          items: []  
        });  
        
        const bodystring = JSON.stringify({  
          'Title': document.getElementById('idFullName')["value"],
          'Address': document.getElementById('idAddress')["value"],
          'Mobile': document.getElementById('idPhoneNumber')["value"],
          'EmailID': document.getElementById('idEmailId')["value"]  
        });  
        
        this.props.spHttpClient.post(`${this.props.siteUrl}/_api/web/lists/getbytitle('${this.props.listName}')/items`,  
        SPHttpClient.configurations.v1,  
        {  
          headers: {  
            'Accept': 'application/json;odata=nometadata',  
            'Content-type': 'application/json;odata=nometadata',  
            'odata-version': ''  
          },  
          body: body  
        })  
        .then((responseSPHttpClientResponse): Promise<IListItem=> {  
          return response.json();  
        })  
        .then((itemIListItem): void => {  
          this.setState({  
            status: `Item '${item.Title}' (ID: ${item.ID}) successfully created`,  
            items: [item]
          });
          this.getListData();
        this.clear();
        }, (errorany): void => {  
          this.setState({  
            status: 'Error while creating the item: ' + error,  
            items: []  
          });
          this.getListData();
        this.clear(); 
        }); 
        this.getListData();
        this.clear();
      }
  118. UPDATE-
  119. private updateItem(): void {  
        this.setState({  
          status: 'Updating Item ...',  
          items: []  
        });  
        
        const bodystring = JSON.stringify({  
          'Title': document.getElementById('idFullName')["value"],
          'Address': document.getElementById('idAddress')["value"],
          'Mobile': document.getElementById('idPhoneNumber')["value"],
          'EmailID': document.getElementById('idEmailId')["value"]  
        });  

        this.props.spHttpClient.post(`${this.props.siteUrl}/_api/web/lists/getbytitle('${this.props.listName}')/items(${this.listItemId})`,  
          SPHttpClient.configurations.v1,  
          {  
            headers: {  
              'Accept': 'application/json;odata=nometadata',  
              'Content-type': 'application/json;odata=nometadata',  
              'odata-version': '',  
              'IF-MATCH': '*',  
              'X-HTTP-Method': 'MERGE'  
            },  
            body: body  
          })  
          .then((responseSPHttpClientResponse): void => {  
            this.setState({  
              status: `Item successfully updated`,  
              items: []  
            });
            this.getListData();
            this.clear();
          }, (errorany): void => {  
            this.setState({  
              status: `Error updating item: ${error}`,  
              items: []  
            });
            this.getListData();
            this.clear();  
          });
          this.getListData();
          this.clear(); 
      }
  120. DELETE-
  121. private deleteItem() {  
        if (!window.confirm('Are you sure you want to delete this item?')) {  
          return;  
        }  
        
        this.setState({  
          status: 'Deleting Item ...',  
          items: []  
        });  
        
        return this.props.spHttpClient.post(`${this.props.siteUrl}/_api/web/lists/getbytitle('${this.props.listName}')/items(${this.listItemId})`,  
        SPHttpClient.configurations.v1,  
        {  
          headers: {  
            'Accept': 'application/json;odata=nometadata',  
            'Content-type': 'application/json;odata=verbose',  
            'odata-version': '',  
            'IF-MATCH': '*',  
            'X-HTTP-Method': 'DELETE'  
          }  
        }).then((responseSPHttpClientResponse): void => {
          this.setState({  
            status: `Item successfully deleted`,  
            items: []  
          });
          this.getListData();
          this.clear();
        }, (errorany): void => {
          alert(`${error}`);
        });
        this.getListData();
        this.clear();
      }
  122. READ-
  123. private getListData() {
        this.props.spHttpClient.get(`${this.props.siteUrl}/_api/web/lists/getbytitle('${this.props.listName}')/items`SPHttpClient.configurations.v1)
          .then(response => {
            return response.json()
              .then((itemsany): void => {
                let listItemsIListItem[] = items.value;
                this.setState({  
                  status: `Items Count:- ${items.value.length}`,  
                  items: listItems  
                });
              })
              
          })
      }
  124. UPDATE (With Grid Edit Button)-
  125. private UpdateWithGridEditButton(Id){
        this.props.spHttpClient.get(`${this.props.siteUrl}/_api/web/lists/getbytitle('${this.props.listName}')/items?$select=*&$filter=Id eq '${Id}'`SPHttpClient.configurations.v1)
          .then(response => {
            return response.json()
              .then((itemany): void => {
                document.getElementById('idFullName')["value"] = item.value[0].Title;
                document.getElementById('idAddress')["value"] = item.value[0].Address;
                document.getElementById('idEmailId')["value"] = item.value[0].EmailID;
                document.getElementById('idPhoneNumber')["value"] = item.value[0].Mobile;
                this.listItemId = item.value[0].Id;
              });
          });
        
      }
  126. DELETE (WIth Grid Delete Button)-
  127. private DeleteWthGridDeleteButton(Id){
        if (!window.confirm('Are you sure you want to delete this item?')) {  
          return;  
        }
        this.props.spHttpClient.post(`${this.props.siteUrl}/_api/web/lists/getbytitle('${this.props.listName}')/items(${Id})`,  
        SPHttpClient.configurations.v1,  
        {  
          headers: {  
            'Accept': 'application/json;odata=nometadata',  
            'Content-type': 'application/json;odata=verbose',  
            'odata-version': '',  
            'IF-MATCH': '*',  
            'X-HTTP-Method': 'DELETE'  
          }  
        }).then((responseSPHttpClientResponse): void => {
          this.setState({  
            status: `Item successfully deleted`,  
            items: []  
          });
          this.getListData();
          this.clear();
        }, (errorany): void => {
          alert(`${error}`);
        });
      }
  128. CLEAR (To Reset The Input Fields)-
  129. private clear(): void {
        document.getElementById('idFullName')["value"] = "";
        document.getElementById('idAddress')["value"] = "";
        document.getElementById('idEmailId')["value"] = "";
        document.getElementById('idPhoneNumber')["value"] = "";
      }
  130. Now add one variable which will hold item id upon which action is getting performed. For this find beolw code-
  131. constructor (props:ICrudOperationsReactJsspFxWpPropsstate:ICrudOperationsReactJsspFxWpState)
  132. Add below code just before it-
  133. private listItemIdnumber = 0;
      
  134. BEFORE-

  135. AFTER-

  136. Next is file "CrudOperationsReactJsspFxWpWebPart.ts" at location "src\webparts\crudOperationsReactJsspFxWp\".
  137. Here we will add code to initiate site url and spHttpClient. For this find below code-
  138. listName: this.properties.listName
  139. Add code for siteURL and spHttpClient after it-
  140. ,
            spHttpClient: this.context.spHttpClient,  
            siteUrl: this.context.pageContext.web.absoluteUrl
  141. BEFORE-
  142. const elementReact.ReactElement<ICrudOperationsReactJsspFxWpProps> = React.createElement(
          CrudOperationsReactJsspFxWp,
          {
            listName: this.properties.listName
          }
        );
  143. AFTER-
  144. const elementReact.ReactElement<ICrudOperationsReactJsspFxWpProps> = React.createElement(
          CrudOperationsReactJsspFxWp,
          {
            listName: this.properties.listName,
            spHttpClient: this.context.spHttpClient,  
            siteUrl: this.context.pageContext.web.absoluteUrl
          }
        );
  145. Finally add some CSS to css file. For this open file "CrudOperationsReactJsspFxWp.module.scss" at location "src\webparts\crudOperationsReactJsspFxWp\components\".
  146. Add below css at the end of file just before the last closing bracket "}"-
  147. .table.th.tr.td{
        border1px;
        border-stylesolid;
        border-color#DA2128;
        border-spacing0px;
      }
      .getRecord-Button.delRecord-Button{
        color#DA2128;
      }
  148. The code will look like-
  149. BEFORE-

  150. AFTER-

  151. Next look for below css-
  152. // Basic Button
        outlinetransparent;
        positionrelative;
        font-family"Segoe UI WestEuropean","Segoe UI",-apple-system,BlinkMacSystemFont,Roboto,"Helvetica Neue",sans-serif;
        -webkit-font-smoothingantialiased;
        font-size$ms-font-size-m;
        font-weight$ms-font-weight-regular;
        border-width0;
        text-aligncenter;
        cursorpointer;
        displayinline-block;
        padding0 16px;
  153. Add below css just after it-
  154. border-radius.25em;
        margin2px;
  155. Final look-
  156. BEFORE-

  157. AFTER-

  158. Finally Done. Now refresh the workbench. It will appear as below-

  159. Let's play with it. First add a record-
  160. Input some data-

  161. Click on Create Button-

  162. Wow! record inserted in table. Hey, what is this 1st record? 😕 
  163. Don't worry, it is the record, I had created a week ago. As I am refreshing the table, hence all records are getting populated.
  164. Let's edit this record now. For this click on Edit button provided ahead of it. It will load this record in input boxes-

  165. I am updating last digit of mobile number from 0 to 5 and clicking on Update button-

  166. Hurray! My record has been updated successfully.
  167. Now I will try to delete the first record with ID 16. For this I am clicking on Delete button provided ahead to it. It will ask me to whether delete or not-

     
  168. The moment, I say Yes by clicking on OK, it deletes the record and refresh the table.

  169. Now to test the All Data button, I had added one record directly in list-

  170. Now clicked on "All Data" button to load the table. Wow, it loaded all records-

  171. To delete the record using Delete button provided separately, you need to first click on Edit button in grid ahead or that record. It will populate the record in input boxes. Now click on Delete button. It will ask for confirmation. Once you OK it, it will delete and reload the grid.
This way, we can make CRUD operations using SPFx webpart and React JS.
  1. Refer more details upon SPFx WebPart, please visit Microsoft Website.

Update (Date: 14 June 2021):-
  1. In case, if you wish to get the ID of the record created using Save command, it might be possible you won't get here. for this, you need to update "odata=nometadata" with "odata.metadata=minimal".
  2. Or you may update the existing code with below one-
  3. this.context.spHttpClient.post(`${this.context.pageContext.web.absoluteUrl}/_api/web/lists/getbytitle('${this.properties.listName}')/items`,
          SPHttpClient.configurations.v1,
          {
            headers: {
              'Accept': 'application/json;odata.metadata=minimal',
              'Content-type': 'application/json;odata.metadata=minimal',  
              'X-HTTP-Method': 'POST'
            },
            body: body
          }).then((response: SPHttpClientResponse): Promise<IListItem> => {
            return response.json();
          })
          .then((item:IListItem):void=>{
            alert(`Item '${item.Name}' (ID: ${item.ID}) successfully created`)
          }, (error: any): void => {
            alert(`${error}`);
          });

No comments:

Post a Comment

Note: Only a member of this blog may post a comment.