CRUD Operations Using Sharepoint FrameWork And PnP JS Library

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
  • Accept the default CrudProject 
  • Select SharePoint Online only (latest).
  • Select Use the current folder for where to place the files.
  • Select N to require the extension to be installed on each site explicitly when it's being used.
  • Select WebPart as the client-side component type to be created.
  • Accept the default CrudProject as the web part name.
  • Accept the default CrudProjectfor Crud Operations against Sharepoint List as the web part description.
  • Accept the default No javascript web framework as the framework you would like to use.

    CRUD Operations Using Sharepoint FrameWork and PnP JS Library

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

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

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,

  • Bundling files
  • Packaging the solution
  • Connecting to the SharePoint Online
  • Adding and publishing the App package to SharePoint Online.
  • Adding and publishing the assets files to SharePoint Online.

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

  • $url: this is the url of SharePoint online.
  • $assestsLib: This is the document library for Assets, I used the default library “SiteAssets/”

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,

  • The Solution package

    CRUD Operations Using Sharepoint FrameWork and PnP JS Library

  • The Assets files

    CRUD Operations Using Sharepoint FrameWork and PnP JS Library

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