The SharePoint Framework (SPFx) is a new technology that provides full support for client-side SharePoint development.

The SharePoint Development Community (also known as the SharePoint PnP community) is an open-source initiative that controls SharePoint patterns, practices, development documentation, samples, and other relevant open-source initiatives related to SharePoint development.

The first step consists in creating the Sharepoint Framework environnement.

In this article we will understand how to create a webpart with Crud operations for SharePoint List items using SPFx and PnP libraries.

Create the Webpart

  1. Create a new project directory
    md CrudProject

  2. Go to the created directory
    Cd CrudProject

  3. Run the Yeoman SharePoint Generator.
    yo @microsoft/sharepoint

You should see the following message when the scaffold is complete,

CRUD Operations Using Sharepoint FrameWork and PnP JS Library

Now after the creation of the initial webpart we have to load PnP JS file with the following command line:

npm install sp-pnp-js –save

Implement Crud Operations

The first step is that we need to load the PnP Library like below:

  1. import * as pnp from 'sp-pnp-js';

Then we have to create the profileList.

CRUD Operations Using Sharepoint FrameWork and PnP JS Library

Then add three columns ProfileId, ProfileName, ProfileJob,

CRUD Operations Using Sharepoint FrameWork and PnP JS Library

We will then create the user interface like below,

CRUD Operations Using Sharepoint FrameWork and PnP JS Library

An event listener will be associated to each button,

  1. private AddEventListeners() : void{
  2. document.getElementById('AddSPItem').addEventListener('click',()=>this.AddSPItem());
  3. document.getElementById('UpdateSPItem').addEventListener('click',()=>this.UpdateSPItem());
  4. document.getElementById('DeleteSPItem').addEventListener('click',()=>this.DeleteSPItem());
  5. }
  6. he CRUD operations will be implemented using PnP Libraries:
  7. AddSPItem()
  8. {
  9. pnp.sp.web.lists.getByTitle('ProfileList').items.add({
  10. ProfileName : document.getElementById('ProfileName')["value"],
  11. ProfileJob : document.getElementById('ProfileJob')["value"]
  12. });
  13. alert("Record with Profile Name : "+ document.getElementById('ProfileName')["value"] + " Added !");
  14. }
  15. UpdateSPItem()
  16. {
  17. var ProfileId = this.domElement.querySelector('input[name = "ProfileId"]:checked')["value"];
  18. pnp.sp.web.lists.getByTitle("ProfileList").items.getById(ProfileId).update({
  19. ProfileName : document.getElementById('ProfileName')["value"],
  20. ProfileJob : document.getElementById('ProfileJob')["value"]
  21. });
  22. alert("Record with Profile ID : "+ ProfileId + " Updated !");
  23. }
  24. DeleteSPItem()
  25. {
  26. var ProfileId = this.domElement.querySelector('input[name = "ProfileId"]:checked')["value"];
  27. pnp.sp.web.lists.getByTitle("ProfileList").items.getById(ProfileId).delete();
  28. alert("Record with Profile ID : "+ ProfileId + " Deleted !");
  29. }

CrudProjectWebPart.ts file

The TypeScript file contents is as shown below,

  1. import pnp from 'sp-pnp-js';
  2. import { Version } from '@microsoft/sp-core-library';
  3. import {
  4. BaseClientSideWebPart,
  5. IPropertyPaneConfiguration,
  6. PropertyPaneTextField
  7. } from '@microsoft/sp-webpart-base';
  8. import { escape } from '@microsoft/sp-lodash-subset';
  9. import styles from './CrudProjectWebPart.module.scss';
  10. import * as strings from 'CrudProjectWebPartStrings';
  11. // import { ICrudProjectWebPartProps } from './ICrudProjectWebPartProps';
  12. export interface ICrudProjectWebPartProps {
  13. description: string;
  14. }
  15. export interface ISPList {
  16. ID: string;
  17. ProfileName: string;
  18. ProfileJob: string;
  19. }
  20. export default class CrudProjectWebPart extends BaseClientSideWebPart<ICrudProjectWebPartProps> {
  21. private AddEventListeners() : void{
  22. document.getElementById('AddSPItem').addEventListener('click',()=>this.AddSPItem());
  23. document.getElementById('UpdateSPItem').addEventListener('click',()=>this.UpdateSPItem());
  24. document.getElementById('DeleteSPItem').addEventListener('click',()=>this.DeleteSPItem());
  25. }
  26. private _getSPItems(): Promise<ISPList[]> {
  27. return pnp.sp.web.lists.getByTitle("ProfileList").items.get().then((response) => {
  28. return response;
  29. });
  30. }
  31. private getSPItems(): void {
  32. this._getSPItems()
  33. .then((response) => {
  34. this._renderList(response);
  35. });
  36. }
  37. private _renderList(items: ISPList[]): void {
  38. let html: string = '<table class="TFtable" border=1 width=style="bordercollapse: collapse;">';
  39. html += `<th></th><th>ProfileId</th><th>Name</th><th>Job</th>`;
  40. if (items.length>0)
  41. {
  42. items.forEach((item: ISPList) => {
  43. html += `
  44. <tr>
  45. <td> <input type="radio" id="ProfileId" name="ProfileId" value="${item.ID}"> <br> </td>
  46. <td>${item.ID}</td>
  47. <td>${item.ProfileName}</td>
  48. <td>${item.ProfileJob}</td>
  49. </tr>
  50. `;
  51. });
  52. }
  53. else
  54. {
  55. html +="No records...";
  56. }
  57. html += `</table>`;
  58. const listContainer: Element = this.domElement.querySelector('#DivGetItems');
  59. listContainer.innerHTML = html;
  60. }
  61. public render(): void {
  62. this.domElement.innerHTML = `
  63. <div class="parentContainer" style="background-color: white">
  64. <div class="ms-Grid-row ms-bgColor-themeDark ms-fontColor-white ${styles.row}">
  65. <div class="ms-Grid-col ms-u-lg
  66. ms-u-xl8 ms-u-xlPush2 ms-u-lgPush1">
  67. </div>
  68. </div>
  69. <div class="ms-Grid-row ms-bgColor-themeDark ms-fontColor-white ${styles.row}">
  70. <div style="background-color:Black;color:white;text-align: center;font-weight: bold;font-size:
  71. x;">Profile Details</div>
  72. </div>
  73. <div style="background-color: white" >
  74. <form >
  75. <br>
  76. <div data-role="header">
  77. <h3>Add SharePoint List Items</h3>
  78. </div>
  79. <div data-role="main" class="ui-content">
  80. <div >
  81. <input id="ProfileName" placeholder="ProfileName"/>
  82. <input id="ProfileJob" placeholder="ProfileJob"/>
  83. <button id="AddSPItem" type="submit" >Add</button>
  84. <button id="UpdateSPItem" type="submit" >Update</button>
  85. <button id="DeleteSPItem" type="submit" >Delete</button>
  86. </div>
  87. </div>
  88. </form>
  89. </div>
  90. <br>
  91. <div style="background-color: white" id="DivGetItems" />
  92. </div>
  93. `;
  94. this.getSPItems();
  95. this.AddEventListeners();
  96. }
  97. Protected AddSPItem()
  98. {
  99. pnp.sp.web.lists.getByTitle('ProfileList').items.add({
  100. ProfileName : document.getElementById('ProfileName')["value"],
  101. ProfileJob : document.getElementById('ProfileJob')["value"]
  102. });
  103. alert("Record with Profile Name : "+ document.getElementById('ProfileName')["value"] + " Added !");
  104. }
  105. Protected UpdateSPItem()
  106. {
  107. var ProfileId = this.domElement.querySelector('input[name = "ProfileId"]:checked')["value"];
  108. pnp.sp.web.lists.getByTitle("ProfileList").items.getById(ProfileId).update({
  109. ProfileName : document.getElementById('ProfileName')["value"],
  110. ProfileJob : document.getElementById('ProfileJob')["value"]
  111. });
  112. alert("Record with Profile ID : "+ ProfileId + " Updated !");
  113. }
  114. Protected DeleteSPItem()
  115. {
  116. var ProfileId = this.domElement.querySelector('input[name = "ProfileId"]:checked')["value"];
  117. pnp.sp.web.lists.getByTitle("ProfileList").items.getById(ProfileId).delete();
  118. alert("Record with Profile ID : "+ ProfileId + " Deleted !");
  119. }
  120. protected get dataVersion(): Version {
  121. return Version.parse('1.0');
  122. }
  123. protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration {
  124. return {
  125. pages: [
  126. {
  127. header: {
  128. description: strings.PropertyPaneDescription
  129. },
  130. groups: [
  131. {
  132. groupName: strings.BasicGroupName,
  133. groupFields: [
  134. PropertyPaneTextField('description', {
  135. label: strings.DescriptionFieldLabel
  136. })
  137. ]
  138. }
  139. ]
  140. }
  141. ]
  142. };
  143. }
  144. }

getSPItems

This will retrieve the list items and display within the div element declared in the render method.

AddEventListeners

This will associate the button’s events to their related methods.

Test the Web part in SharePoint Online

The deployment process can be done through a deployment PowerShell script, which automates the deployment process by handling all the necessary steps including,

There are some parameters on the script that have been to set before,

Before executing the script, run the following cmdlet,

Install-Module SharePointPnPPowerShellOnline

Then we run the script using the following command,

.\deployment.ps1

That will automatically ask you to enter the email and password to connect to your SharePoint Online,

CRUD Operations Using Sharepoint FrameWork and PnP JS Library

After the script has been executed, you’ll see a Deployment successful message like below,

CRUD Operations Using Sharepoint FrameWork and PnP JS Library

Now you can check that the concerned files are uploaded to the related libraries,

Preview the web part

Now, let’s test the Web part in SharePoint online.

To preview your web part, you can add it on any page,

CRUD Operations Using Sharepoint FrameWork and PnP JS Library

The UI of our webpart will look like below,

CRUD Operations Using Sharepoint FrameWork and PnP JS Library
Add a user profile

You can add a new profile by inserting the name and the job then click on Add which will create a new user like below,

CRUD Operations Using Sharepoint FrameWork and PnP JS Library

Then you can see that a new user has been added,

CRUD Operations Using Sharepoint FrameWork and PnP JS Library

You can update the users anytime by selecting the related profile and updating the information then click on Update button,

CRUD Operations Using Sharepoint FrameWork and PnP JS Library

CRUD Operations Using Sharepoint FrameWork and PnP JS Library

The concerned user has been updated then,

CRUD Operations Using Sharepoint FrameWork and PnP JS Library

To delete a profile user, you can select the related user then click on delete button,

CRUD Operations Using Sharepoint FrameWork and PnP JS Library

You can find the project files used in this solution uploaded at GitHub,

  • The webpart solution
    https://github.com/FullStackRafik/SPFxCrudWebpArt

  • The deployment script
    https://github.com/FullStackRafik/DeploySPFxToSPOnline