Getting started with SharePoint Framework using PnP JS library

This article explains the steps to create a SharePoint Framework and access SharePoint using PnP JavaScript Library

SharePoint Framework is a new development model which eases the developer life for developing and testing the application in automated ways when compared to other development models and it also enriches the user’s UI experience in SharePoint sites.

Below are some references for developing the SharePoint framework applications,

Introduction to SharePoint Framework Development This link contains the summarization of the tools required for developing framework model web part, development perquisites and how to create a project

Tutorials and Walkthroughs This contains the below tutorial links to the starting point for SharePoint Framework development

In this article, we will create a HelloWorld Web Part to talk to SharePoint by using PnP JavaScript Library (PnP JS version of Tutorial 2: HelloWorld Web Part, Talking to SharePoint).

Before creating a SharePoint Framework solution, we have to ensure the below items for development,

  • The environment should be in Office 365 developer tenant, due to the current release is initial preview stage
  • SharePoint site should be a developer site collection
  • Node Js and npmjs tools.
  • Yeoman and Gulp should be installed globally.
  • Yeoman SharePoint Generator should be installed globally.
  • Upload the workbench.aspx file to Documents library in a developer site collection.

Create a new SharePoint Framework project:

  • Open any command line tool. I preferred to use Cmder.
  • Navigate to a folder or create a new folder
  • Run the Yeoman generator to create SharePoint Framework solution package
  • Fill the details required for generator to create a new SharePoint solution.

    SharePoint Framework Project Generator
    Fig 1: SharePoint Framework Project Generator
  • After getting the Success message,
    We can also run “gulp serve” command to host the application and start the local workbench. The local workbench enables us to test the application in many ways.We can also launch the workbench.aspx file from SharePoint site to test the application in SharePoint site.
  • To include PnP JS library to the project, run the following npm command

    [code language=”ps”]
    npm i sp-pnp-js –save-dev
    [/code]

    npm command for adding PnP JS library
    Fig 2: npm command for adding PnP JS library
  • The command will include PnP js file and its dependencies to the project folder.

    Successfull installation of PnP js and its dependencies
    Fig 3: Successfull installation of PnP js and its dependencies

Now we have created the solution structure and with the dependencies. Next, we will see on updating the code in the generated project to retrieve the list information and render with custom styles.

Updating the Code:

The below steps and code snippets used to populate the visible lists in SharePoint framework from the SharePoint site.

Navigate to solution folder
Define List Model
Style the DOM structure
Retrieve Mockup information for local workbench
Retrieve actual information from SharePoint site
Render the data based on the environment type (Local / SharePoint)

Navigate to solution folder

    • Open the solution folder in source code editor. I’ll prefer to use Visual Studio Code, because it is a light weight and also available across platforms.

      SharePoint Framework Folder Structure
      Fig 4: SharePoint Framework Folder Structure
    • Expand src > webparts > PnPjsHelloWorld folder and then select PnPjsHelloWorldWebPart.ts file to edit the code.

      WebPart File
      Fig 5: WebPart File

Define List Model

  • Define the interface for List Model in the code. To define that open PnPjsHelloWorldWebPart.ts file.
  • Paste the following interface code just below the PnPJsHelloWorldWebPart class

    [code language=”csharp”]
    export interface ISPList {
    Title: string;
    Id: string;
    }
    [/code]

    The ISPList interface holds the SharePoint lists title and id information

Style DOM structure

SharePoint uses the SaaS language for stylesheets generation. Sass extends CSS language and allows you to use features like variables, nested rules, inline imports in to organize and create efficient style sheets for your web parts. The SharePoint Framework already comes with a SCSS compiler that converts your Sass files to normal CSS files and also provides a typed version to use it in during development.

Follow the to add a styles to the entire list collection and particle list row,

  • Open PnPjsHelloWorld.Module.scss file
  • Add the following styles below to the .button style,

    [code language=”css”]
    .list {
    color: #333333;
    font-family: ‘Segoe UI Regular WestEuropean’, ‘Segoe UI’, Tahoma, Arial, sans-serif;
    font-size: 14px;
    font-weight: normal;
    box-sizing: border-box;
    margin: 10;
    padding: 10;
    line-height: 50px;
    list-style-type: none;
    box-shadow: 0 4px 4px 0 rgba(0, 0, 0, 0.2), 0 25px 50px 0 rgba(0, 0, 0, 0.1);
    }

    .listItem {
    color: #333333;
    vertical-align: center;
    font-family: ‘Segoe UI Regular WestEuropean’, ‘Segoe UI’, Tahoma, Arial, sans-serif;
    font-size: 14px;
    font-weight: normal;
    box-sizing: border-box;
    margin: 0;
    padding: 0;
    box-shadow: none;
    *zoom: 1;
    padding: 9px 28px 3px;
    position: relative;
    }
    [/code]

  • Save the file

After running the gulp build or run tasks, the styles from. scss file are converted to the .css file and generates the corresponding typings in .scss.ts file.SO, we can import the styles and used as a reference in other typescript file.
To import the styles in the web part file by adding below line (Auto generated),

[code language=”csharp”]import styles from ‘./PnPjsHelloWorld.module.scss’;[/code]

By using the below syntax, we can add style references to the typescript files,

[code language=”csharp”]${styles.style_name}[/code]

Retrieve List info (mock data) from local environment

We have to ensure, local workbench to display some data in the web part to simulate as same as in SharePoint site. For that we have to create mockup data

  • Create a new file “MockHttpClient.ts” inside the src > webparts > PnPjsHelloWorld
  • Copy the following code to the file

    [code language=”csharp”]
    //import ISPList interface to this file from PnPjsHelloWorldWebPart.ts
    import { ISPList } from ‘./PnPjsHelloWorldWebPart’;

    //Declare ISPList array and returns the array of items whenever MockHttpClient.get() method called
    export default class MockHttpClient {

    private static _items: ISPList[] = [{ Title: ‘Mock List’, Id: ‘1’ }];

    public static get(restUrl: string, options?: any): Promise<ISPList[]> {
    return new Promise<ISPList[]>((resolve) =< {
    resolve(MockHttpClient._items);
    });
    }
    }
    [/code]

  • Save the file.

Then we have to import the MockHttpClient module in PnPjsHelloWorldWebPart.ts file. So

  • Open PnPjsHelloWorldWebPart.ts file from the editor.
  • Copy the following code just below the line import { IPnPjsHelloWorldWebPartProps } from ‘./IPnPjsHelloWorldWebPartProps’;

    [code lanuage=”csharp”]import MockHttpClient from ‘./MockHttpClient’;[/code]

  • Add the following private method inside the PnPjsHelloWorldWebPart class

    [code language=”csharp”]
    private _getMockListData(): Promise<ISPList[]> {
    return MockHttpClient.get(this.context.pageContext.web.absoluteUrl).then(() => {
    const listData: ISPList[] = [
    { Title: ‘Mock List’, Id: ‘1’ },
    { Title: ‘Mock List Two’, Id: ‘2’ },
    { Title: ‘Mock List Three’, Id: ‘3’ }
    ];
    return listData;
    }) as Promise<ISPList[]>;
    }
    [/code]

  • Save the file

Render the retrieved lists information

We have to render two different information based on the workbench environment. For Local workbench, we have to render the mockup data. For SharePoint site workbench, we have to render the actual lists information.

  • To identify the environment, first import the EnvironmentType module to PnPjsHelloWorldWebPart.ts file. So Open PnPjsHelloWorldWebPart.ts file
  • Add the following line to the import section in top of the page.

    [code language=”csharp”]import { EnvironmentType } from ‘@microsoft/sp-client-base’;[/code]

  • Add the following private method to determine the environment and based on that, call the required get methods to retrieve the array of ISPList collection for appropriate environment. _getMockListData method used to get the mock data and render the items in local environment. _getListData method used to get the actual SharePoint data from SharePoint environment.

    [code language=”csharp”]
    private _renderListAsync(): void {
    // Local environment
    if (this.context.environment.type === EnvironmentType.Local) {
    this._getMockListData().then((response) => {
    this._renderList(response);
    }); }
    //SharePoint Site environment
    else {
    this._getListData()
    .then((response) => {
    this._renderList(response);
    });
    }
    }
    [/code]

  • To use the PnP JS component in _getListData method, add the below import statement to the import section in top of the PnPjsHelloWorldWebPart.ts file
    [code language=”js”]
    import pnp from ‘sp-pnp-js’;
    [/code]
  • The below _getListData method, used to get the SharePoint list information using PnP JS core component.
    [code language=”js”]
    private _getListData(): Promise<ISPList[]> {
    return pnp.sp.web.lists.filter(‘Hidden eq false’).select(‘Title,Id’).get().then((response) => {
    return response;
    });
    }
    [/code]
  • Add the following method to render the information to the UI based on the retrieved ISPList array collection,

    [code language=”csharp”]
    private _renderList(items: ISPList[]): void {
    let html: string = ”;
    items.forEach((item: ISPList) => {
    html += `
    <ul class="${styles.list}">
    <li class="${styles.listItem}">
    <span class="ms-font-l">${item.Title}</span>
    </li>
    </ul>`;
    });

    const listContainer: Element = this.domElement.querySelector(‘#spListContainer’);
    listContainer.innerHTML = html;
    }

    [/code]

We can apply the style to the element from another file by importing the css module.
${styles.list} applies the style to the ul element, the style information is retrieved from

  • Modify the WebPart render method contents by replacing with following one,

    [code language=”csharp”]
    this.domElement.innerHTML = `
    <div class="${styles.pnPjsHelloWorld}">
    <div class="${styles.container}">
    <div class="ms-Grid-row ms-bgColor-themeDark ms-fontColor-white ${styles.row}">
    <div class="ms-Grid-col ms-u-lg10 ms-u-xl8 ms-u-xlPush2 ms-u-lgPush1">
    <span class="ms-font-xl ms-fontColor-white">Welcome to SharePoint!</span>
    <p class="ms-font-l ms-fontColor-white">Customize SharePoint experiences using Web Parts.</p>
    <p class="ms-font-l ms-fontColor-white">${this.properties.description}</p>
    <a href="https://github.com/SharePoint/sp-dev-docs/wiki" class="ms-Button ${styles.button}">
    <span class="ms-Button-label">Learn more</span>
    </a>
    </div>
    </div>
    <div id="spListContainer" />
    </div>
    </div>`;

    this._renderListAsync();

    [/code]

  • Save the file

Test the application

  • Run “gulp serve” command in command line tool. Which compiles the project and generates the js and css files required for the application.
  • Local workbench automatically started after running the command. The default location for local workbench is http://localhost:4321/temp/workbench.html
    The typescript files and PnP js files are bundled into http://localhost:4321/dist/pn-pjs-hello-world.bundle.js

     Served Files from localhost
    Fig 6: Served Files from localhost
  • Click + icon and Select Web Part Name “PnPjsHelloWorld” to insert the web part to the workbench to test the application. In local workbench, we will get the mockup data in the output.

    Workbench with options
    Fig 7: Workbench with options
  • Open SharePoint site where we have uploaded workbench.aspx file to test the application. Allow unsafe scripts to load in the page to access JavaScript and other dependent files from localhost.

    Local Workbench output with mockup data
    Fig 8: Local Workbench output with mockup data
  • In the workbench page, click + icon and then select the web part name to insert the SharePoint framework web part to the page

    Site Workbench with actual data
    Fig 8: Site Workbench with actual data

Conclusion:

In this article, we have learned on how to use a PnP JavaScript library to access SharePoint list collection and render the data in SharePoint Framework web part.

Shantha Kumar
Shantha Kumar
Articles: 278

24,849 Comments

  1. Hi Kumar,

    The moment i add pnp reference(import pnp from ‘sp-pnp-js’;) i am getting the below error. Any idea?

    Error – typescript – node_modules\@types\core-js\index.d.ts(781,11): error TS230
    0: Duplicate identifier ‘Promise’.
    Error – typescript – node_modules\@types\core-js\index.d.ts(867,13): error TS230
    0: Duplicate identifier ‘Promise’.
    Error – typescript – node_modules\@types\whatwg-fetch\index.d.ts(14,15): error T
    S2300: Duplicate identifier ‘Headers’.
    Error – typescript – node_modules\@types\whatwg-fetch\index.d.ts(31,14): error T
    S2300: Duplicate identifier ‘BodyInit’.
    Error – typescript – node_modules\@types\whatwg-fetch\index.d.ts(41,14): error T
    S2300: Duplicate identifier ‘RequestInfo’.
    Error – typescript – node_modules\@types\whatwg-fetch\index.d.ts(42,15): error T
    S2300: Duplicate identifier ‘Request’.
    Error – typescript – node_modules\@types\whatwg-fetch\index.d.ts(61,11): error T
    S2300: Duplicate identifier ‘Request’.
    Error – typescript – node_modules\@types\whatwg-fetch\index.d.ts(78,6): error TS
    2300: Duplicate identifier ‘RequestMode’.
    Error – typescript – node_modules\@types\whatwg-fetch\index.d.ts(79,6): error TS
    2300: Duplicate identifier ‘RequestCredentials’.
    Error – typescript – node_modules\@types\whatwg-fetch\index.d.ts(80,6): error TS
    2300: Duplicate identifier ‘RequestCache’.
    Error – typescript – node_modules\@types\whatwg-fetch\index.d.ts(84,15): error T
    S2300: Duplicate identifier ‘Response’.
    Error – typescript – node_modules\@types\whatwg-fetch\index.d.ts(102,11): error
    TS2300: Duplicate identifier ‘Response’.
    Error – typescript – node_modules\@types\whatwg-fetch\index.d.ts(109,6): error T
    S2300: Duplicate identifier ‘ResponseType’.
    Error – typescript – typings\es6-promise\es6-promise.d.ts(12,15): error TS2300:
    Duplicate identifier ‘Promise’.
    Error – typescript – typings\es6-promise\es6-promise.d.ts(43,16): error TS2300:
    Duplicate identifier ‘Promise’.
    Error – typescript – typings\whatwg-fetch\whatwg-fetch.d.ts(8,15): error TS2300:
    Duplicate identifier ‘Request’.
    Error – typescript – typings\whatwg-fetch\whatwg-fetch.d.ts(22,2): error TS2403:
    Subsequent variable declarations must have the same type. Variable ‘headers’ m
    ust be of type ‘HeadersInit’, but here has type ‘string[] | Headers | { [index:
    string]: string; }’.
    Error – typescript – typings\whatwg-fetch\whatwg-fetch.d.ts(24,2): error TS2403:
    Subsequent variable declarations must have the same type. Variable ‘mode’ must
    be of type ‘RequestMode’, but here has type ‘string | “same-origin” | “navigate
    ” | “no-cors” | “cors”‘.
    Error – typescript – typings\whatwg-fetch\whatwg-fetch.d.ts(25,2): error TS2403:
    Subsequent variable declarations must have the same type. Variable ‘credential
    s’ must be of type ‘RequestCredentials’, but here has type ‘string | “same-origi
    n” | “omit” | “include”‘.
    Error – typescript – typings\whatwg-fetch\whatwg-fetch.d.ts(26,2): error TS2403:
    Subsequent variable declarations must have the same type. Variable ‘cache’ mus
    t be of type ‘RequestCache’, but here has type ‘string | “default” | “no-store”
    | “reload” | “no-cache” | “force-cache” | “only-if-cached”‘.
    Error – typescript – typings\whatwg-fetch\whatwg-fetch.d.ts(36,14): error TS2300
    : Duplicate identifier ‘RequestMode’.
    Error – typescript – typings\whatwg-fetch\whatwg-fetch.d.ts(37,14): error TS2300
    : Duplicate identifier ‘RequestCredentials’.
    Error – typescript – typings\whatwg-fetch\whatwg-fetch.d.ts(38,14): error TS2300
    : Duplicate identifier ‘RequestCache’.
    Error – typescript – typings\whatwg-fetch\whatwg-fetch.d.ts(40,15): error TS2300
    : Duplicate identifier ‘Headers’.
    Error – typescript – typings\whatwg-fetch\whatwg-fetch.d.ts(58,15): error TS2300
    : Duplicate identifier ‘Response’.
    Error – typescript – typings\whatwg-fetch\whatwg-fetch.d.ts(71,14): error TS2300
    : Duplicate identifier ‘ResponseType’.
    Error – typescript – typings\whatwg-fetch\whatwg-fetch.d.ts(74,2): error TS2687:
    All declarations of ‘status’ must have identical modifiers.
    Error – typescript – typings\whatwg-fetch\whatwg-fetch.d.ts(76,2): error TS2403:
    Subsequent variable declarations must have the same type. Variable ‘headers’ m
    ust be of type ‘HeadersInit’, but here has type ‘HeaderInit’.
    Error – typescript – typings\whatwg-fetch\whatwg-fetch.d.ts(80,14): error TS2300
    : Duplicate identifier ‘BodyInit’.
    Error – typescript – typings\whatwg-fetch\whatwg-fetch.d.ts(81,14): error TS2300
    : Duplicate identifier ‘RequestInfo’.
    Error – ‘typescript’ sub task errored after 3.4 s
    “TypeScript error(s) occurred.”

    • In latest PnP-JS library, team is moving type script definitions from typing folder to @types. Due to that, during compilation, we are getting this duplicate references.
      Solution:
      Remove the following references from typings\tsd.d file
      /// <reference path=”es6-collections/es6-collections.d.ts” />
      /// <reference path=”es6-promise/es6-promise.d.ts” />
      /// <reference path=”whatwg-fetch/whatwg-fetch.d.ts” />

      I hope this may solve your duplicate problem.

  2. I am getting error when importing: import * as spns from “sp-pnp-js”;

    The error is Error: (SystemJS) Unexpected token < … SyntaxError: Unexpected token <
    at eval ()
    at Object.eval …

    In js file i can see this happens when var spns = require(“sp-pnp-js”);

  3. I’m getting a bunch of these react errors when trying to run gulp serve. Any ideas?

    Error – typescript – node_modules\@types\react\index.d.ts(2591,13): error TS2403: Subsequent variable declarations must
    have the same type. Variable ‘linearGradient’ must be of type ‘SVGProps’, but here has type ‘SVGProps’.

Comments are closed.