In the series of SPFx tutorials, today we are going to learn about CRUD operations in SPFx using SPHttpClient. In the next article, we will learn CRUD operation using PNP.

SharePoint Framework CRUD Operations using SPHttpClient

  1. Create a list with Name EmployeeDetails. Add column Age. We will use the Title column to Save the Full name and the Age column to add the age of the employee.
  2. I have created a folder with the name SPFxCrud on your local machine under the E folder.
  3. Copy the folder path and open the path in the command prompt by using the below command:
    cd E:\Office365Notes\SPFxCrud

  4. Scaffold the SPFx solution using Yeoman Generator
    yo @microsoft/sharepoint

  5. Give the webpart name and other details as shown below


  6. Open the solution in VS Code. You can use the "Code ." command in the command prompt directly to open the solution in VS Code.
  7. We are going to write the entire logic for CRUD operations in the .tsx file. For that, we need the context of SharePoint in the .tsx file.
  8. We will first define a property for passing the SharePoint context from our .ts file to the .tsx file.
  9. Add a property context in the ISpFxCrudProps.ts file as shown below:
    export interface ISpFxCrudProps {
      description: string;
      context: any;
    }
    
  10. Then initialize the context from the SpFxCrudWebPart.ts file as shown below


  11. Update the default HTML (JSX) in SPFxCrud.tsx with below HTML (JSX)
     <div className={styles.helloWorldReact}>
            <div className={styles.container}>
              <div className={styles.row}>
                <div className={styles.column}>
                  <p className={styles.description}>{escape(this.props.description)}</p>
                  <div className={styles.itemField}>
                    <div className={styles.fieldLabel}>Item ID:</div>
                    <input type="text" id='itemId'></input>
                  </div>
                  <div className={styles.itemField}>
                    <div className={styles.fieldLabel}>Full Name</div>
                    <input type="text" id='fullName'></input>
                  </div>
                  <div className={styles.itemField}>
                    <div className={styles.fieldLabel}>Age</div>
                    <input type="text" id='age'></input>
                  </div>
                  <div className={styles.itemField}>
                    <div className={styles.fieldLabel}>All Items:</div>
                    <div id="allItems"></div>
                  </div>
                  <div className={styles.buttonSection}>
                    <div className={styles.button}>
                      <span className={styles.label} onClick={this.createItem}>Create</span>
                    </div>
                    <div className={styles.button}>
                      <span className={styles.label} onClick={this.getItemById}>Read</span>
                    </div>
                    <div className={styles.button}>
                      <span className={styles.label} onClick={this.getAllItems}>Read All</span>
                    </div>
                    <div className={styles.button}>
                      <span className={styles.label} onClick={this.updateItem}>Update</span>
                    </div>
                    <div className={styles.button}>
                      <span className={styles.label} onClick={this.deleteItem}>Delete</span>
                    </div>
                  </div>
                </div>
              </div>
            </div>
          </div>
  12. Import the below libraries in the file at the top, where other dependencies are imported.
    import {
      SPHttpClient,
      SPHttpClientResponse
    } from '@microsoft/sp-http';
  13. When we will add the functions for CRUD Operations, our tax file will look like below


  14. When you add the functions for CRUD Operations, your .tsx file will look like below:
    import * as React from 'react';
    import styles from './SpFxCrud.module.scss';
    import { ISpFxCrudProps } from './ISpFxCrudProps';
    import { escape } from '@microsoft/sp-lodash-subset';
    import {
      SPHttpClient,
      SPHttpClientResponse
    } from '@microsoft/sp-http';
    
    export default class SpFxCrud extends React.Component<ISpFxCrudProps, {}> {
      public render(): React.ReactElement<ISpFxCrudProps> {
        return (
          <div className={styles.SpFxCrud}>
    <div className={styles.container}> <div className={styles.row}> <div className={styles.column}> <p className={styles.description}>{escape(this.props.description)}</p> <div className={styles.itemField}> <div className={styles.fieldLabel}>Item ID:</div> <input type="text" id='itemId'></input> </div> <div className={styles.itemField}> <div className={styles.fieldLabel}>Full Name</div> <input type="text" id='fullName'></input> </div> <div className={styles.itemField}> <div className={styles.fieldLabel}>Age</div> <input type="text" id='age'></input> </div> <div className={styles.itemField}> <div className={styles.fieldLabel}>All Items:</div> <div id="allItems"></div> </div> <div className={styles.buttonSection}> <div className={styles.button}> <span className={styles.label} onClick={this.createItem}>Create</span> </div> <div className={styles.button}> <span className={styles.label} onClick={this.getItemById}>Read</span> </div> <div className={styles.button}> <span className={styles.label} onClick={this.getAllItems}>Read All</span> </div> <div className={styles.button}> <span className={styles.label} onClick={this.updateItem}>Update</span> </div> <div className={styles.button}> <span className={styles.label} onClick={this.deleteItem}>Delete</span> </div> </div> </div> </div> </div> </div> ); } // Create Item private createItem = (): void => { const body: string = JSON.stringify({ 'Title': document.getElementById("fullName")['value'], 'Age': document.getElementById("age")['value'] }); this.props.context.spHttpClient.post(`${this.props.context.pageContext.web.absoluteUrl}/_api/web/lists/getbytitle('EmployeeDetails')/items`, SPHttpClient.configurations.v1, { headers: { 'Accept': 'application/json;odata=nometadata', 'Content-type': 'application/json;odata=nometadata', 'odata-version': '' }, body: body }) .then((response: SPHttpClientResponse) => { if (response.ok) { response.json().then((responseJSON) => { console.log(responseJSON); alert(`Item created successfully with ID: ${responseJSON.ID}`); }); } else { response.json().then((responseJSON) => { console.log(responseJSON); alert(`Something went wrong! Check the error in the browser console.`); }); } }).catch(error => { console.log(error); }); } // Get Item by ID private getItemById = (): void => { const id: number = document.getElementById('itemId')['value']; if (id > 0) { this.props.context.spHttpClient.get(this.props.context.pageContext.web.absoluteUrl + `/_api/web/lists/getbytitle('EmployeeDetails')/items(${id})`, SPHttpClient.configurations.v1, { headers: { 'Accept': 'application/json;odata=nometadata', 'odata-version': '' } }) .then((response: SPHttpClientResponse) => { if (response.ok) { response.json().then((responseJSON) => { console.log(responseJSON); document.getElementById('fullName')['value'] = responseJSON.Title; document.getElementById('age')['value'] = responseJSON.Age; }); } else { response.json().then((responseJSON) => { console.log(responseJSON); alert(`Something went wrong! Check the error in the browser console.`); }); } }).catch(error => { console.log(error); }); } else { alert(`Please enter a valid item id.`); } } // Get all items private getAllItems = (): void => { this.props.context.spHttpClient.get(this.props.context.pageContext.web.absoluteUrl + `/_api/web/lists/getbytitle('EmployeeDetails')/items`, SPHttpClient.configurations.v1, { headers: { 'Accept': 'application/json;odata=nometadata', 'odata-version': '' } }) .then((response: SPHttpClientResponse) => { if (response.ok) { response.json().then((responseJSON) => { var html = `<table><tr><th>ID</th><th>Full Name</th><th>Age</th></tr>`; responseJSON.value.map((item, index) => { html += `<tr><td>${item.ID}</td><td>${item.Title}</td><td>${item.Age}</td></li>`; }); html += `</table>`; document.getElementById("allItems").innerHTML = html; console.log(responseJSON); }); } else { response.json().then((responseJSON) => { console.log(responseJSON); alert(`Something went wrong! Check the error in the browser console.`); }); } }).catch(error => { console.log(error); }); } // Update Item private updateItem = (): void => { const id: number = document.getElementById('itemId')['value']; const body: string = JSON.stringify({ 'Title': document.getElementById("fullName")['value'], 'Age': document.getElementById("age")['value'] }); if (id > 0) { this.props.context.spHttpClient.post(`${this.props.context.pageContext.web.absoluteUrl}/_api/web/lists/getbytitle('EmployeeDetails')/items(${id})`, 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((response: SPHttpClientResponse) => { if (response.ok) { alert(`Item with ID: ${id} updated successfully!`); } else { response.json().then((responseJSON) => { console.log(responseJSON); alert(`Something went wrong! Check the error in the browser console.`); }); } }).catch(error => { console.log(error); }); } else { alert(`Please enter a valid item id.`); } } // Delete Item private deleteItem = (): void => { const id: number = parseInt(document.getElementById('itemId')['value']); if (id > 0) { this.props.context.spHttpClient.post(`${this.props.context.pageContext.web.absoluteUrl}/_api/web/lists/getbytitle('EmployeeDetails')/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((response: SPHttpClientResponse) => { if (response.ok) { alert(`Item ID: ${id} deleted successfully!`); } else { alert(`Something went wrong!`); console.log(response.json()); } }); } else { alert(`Please enter a valid item id.`); } } }
  15. You have to update the SpFxCrud.module.scss file with below CSS
    @import "~office-ui-fabric-react/dist/sass/References.scss";
    
    .SpFxCrud {
      .container {
        max-width: 700px;
        margin: 0px auto;
        box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.2), 0 25px 50px 0 rgba(0, 0, 0, 0.1);
      }
    
      .row {
        @include ms-Grid-row;
        @include ms-fontColor-white;
        background-color: $ms-color-themeDark;
        padding: 20px;
      }
    
      .column {
        @include ms-Grid-col;
        @include ms-lg10;
        @include ms-xl8;
        @include ms-xlPush2;
        @include ms-lgPush1;
      }
    
      .title {
        @include ms-font-xl;
        @include ms-fontColor-white;
      }
    
      .subTitle {
        @include ms-font-l;
        @include ms-fontColor-white;
      }
    
      .description {
        @include ms-font-l;
        @include ms-fontColor-white;
      }
    
      .button {
        // Our button
        text-decoration: none;
        height: 32px;
    
        // Primary Button
        min-width: 80px;
        background-color: $ms-color-themePrimary;
        border-color: $ms-color-themePrimary;
        color: $ms-color-white;
    
        // Basic Button
        outline: transparent;
        position: relative;
        font-family: "Segoe UI WestEuropean", "Segoe UI", -apple-system, BlinkMacSystemFont, Roboto, "Helvetica Neue",
          sans-serif;
        -webkit-font-smoothing: antialiased;
        font-size: $ms-font-size-m;
        font-weight: $ms-font-weight-regular;
        border-width: 0;
        text-align: center;
        cursor: pointer;
        display: inline-block;
        margin: 10px;
        .label {
          font-weight: $ms-font-weight-semibold;
          font-size: $ms-font-size-m;
          height: 32px;
          line-height: 32px;
          margin: 0 4px;
          vertical-align: top;
          display: inline-block;
        }
      }
    
      .itemField {
        display: flex;
        padding: 5px;
        .fieldLabel {
          min-width: 100px;
        }
      }
    
      .buttonSection{
        padding-top: 20px;
        display: flex;
      }
    }
    
    
  16. Your UI will look like as below


I hope you have liked this tutorial on SPFx CRUD Operations using SPHTTPClient. In the next article, we will see the CRUD Operations in SPFX using PNP.