Tuesday, 6 September 2022

SharePoint Framework CRUD Operations using SPHttpClient

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:
    1
    cd E:\Office365Notes\SPFxCrud

  4. Scaffold the SPFx solution using Yeoman Generator
    1
    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:
    1
    2
    3
    4
    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)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    <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.
    1
    2
    3
    4
    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:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    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
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    @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