SharePoint Server 2016 : Exploring the Installation of FP 2 and Development of SPF webparts using TypeScript and PnP JS
Introduction
SharePoint Framework for SharePoint Server 2016 was launched in September 2017 as part of Feature Pack 2. This is a major milestone in SharePoint Server history and in this article we will explore in depth how to enable SharePoint Framework in SharePoint Server 2016 and explore how to develop webparts using SPFx.
In the older SharePoint Days, we were mostly using Server Side Object Model to customize SharePoint. Since the code ran within the main W3WP thread, deployments resulted in brief downtime and increased the risk that came along with untested code. Moreover, Server Side code was not feasible with Office 365 based SharePoint Online implementations. To overcome the sharing of the SharePoint thread by the code, Sand boxed solutions were introduced that executed in its own SPUCWorkerProcess. However, they had their own limitations and are in a deprecated stage now.
Later, SharePoint Add-ins were introduced which leveraged the client side development approach and helped developers deploy solutions to Office 365 SharePoint Online as well as On Premise. In addition to it, the Add-ins were installed in the app web which was separate from the main SharePoint Host web creating the required isolation. However, the add-ins had the IFrame and App web dependency which forced developers to use workarounds for the limitations that came along with it (Cross Domain Library for instance). To overcome some of the down sides of Add-ins, developers embraced a mix of Add-in + Client Side Content Editor web part development which exposed the page code and any one with 'Add and Customize Pages' permission could break the existing code from the browser.
Though not a replacement for any of the previous development models, with the SharePoint Framework model, Microsoft is providing an advanced full client side development model which can be used on any platform and with any JavaScript framework like React, Angular, Knockout, Handlebar etc.: to build SharePoint Solutions. It aims at building of client side customization much easier with a streamlined deployment process. SPFx solutions are rendered within the current user context in the current page DOM (not in an IFRAME) which results in faster performance. More over the strong dependency with Visual Studio has been removed and we can use modern web technologies and tools in our preferred development environment to build SPFx solutions. We will go over these development tools in the upcoming sections.
What are we going to do ?
With the help of Feature Pack 2, we can now create SharePoint Framework webparts in SharePoint Server 2016. In this article we will see in detail how to :
- Install and Configure Feature Pack 2 for getting Started with SPFx in SharePoint 2016
- Create a Simple Hello World SPFx Webpart
- Create a SPFx Webpart in SharePoint 2016 to Rretrieve and Display SharePoint List items
- Create a SPFx Webpart to Deploy Site Assets like Site Columns,Content Type and List to SharePoint 2016
- Create a SPFx WebPart that retrieves and Displays User profile Properties using PnP Js and REST API
- Create a complete CRUD SPFx Webpart using PnP JS and REST API to Create/Read/Update/Delete SharePoint List Items
Install and Configure Feature Pack 2
SharePoint Framework has now come to SharePoint Server as part of the Feature Pack 2 that was release on September 10 2017. The announcement of the Feature Pack 2 can be found here
You can download the latest update that contains the Feature Pack 2 from here. Any updates from September 2017 will contain the binary for SharePoint Framework. We will be using the October update as it is the latest release.
Every update released in a month will contain a Language dependent Fix and a language Independent fix . The October Update has :
- Language Independent fix(**KB 4011217) **: 16.0.4600.1002 as Build Number
- Language Dependent fix(KB 4011161) : 16.0.4600.1000 as Build Number
KB 4011217 is the Language Independent October Update but includes Feature Pack 2 that was launched in September as well.
KB 4011217 is the latest update available at the point of writing this article, so lets download it.
Once you have downloaded it, install the Feature Pack 2 in the SharePoint 2016 Server
Accept the agreement and Click on Yes to Continue with the installation.
Accept the agreement and Proceed with the installation.
Once the installation is completed, it will ask for the rebooting of the server.After the system has rebooted, head over to CA and from Servers in the farm, check upgrade status. It will be shown as Upgrade Required.
This is because just like any CU/patch we have to run PSConfig to update the configuration data base and other services.
SharePoint Post Update Configuration using Products Configuration Wizard
Spin up SharePoint 2016 Products Configuration Wizard.
Proceed with the configuration wizard and wait for it to complete which might take some time .
Once Completed, It will show a success message.
SharePoint Post Update Configuration using PSConfig
We can also do the Product configuration using SharePoint Management Shell by running PSConfig cmdlet :
PSConfig.exe -cmd upgrade -inplace b2b -wait -cmd applicationcontent -install -cmd installfeatures -cmd secureresources -cmd services -install
This will take some time and once completed we will get the below success message :
Once the configuration is completed, head over to Central Administration -> Upgrade and Migration -> Check Product and Installation Status. Here we can see the latest update 16.0.4000.1002 installed.
Set up SharePoint Framework Development Environment
Once we have installed the Feature Pack 2 update, let us see how to set up the development environment so that we can kick start with SharePoint Framework development. Below are the required components that we will have to install in the environment.
- Node JS
- Yeoman and Gulp
- Yeoman SharePoint Generator
- Code Editor(Visual Studio Code/Webstorm)
- Postman and Fiddler(optional)
Install Node JS
Node.js is a JavaScript runtime built on Chrome's V8 JavaScript engine. It uses an event-driven, non-blocking I/O model that makes it lightweight and efficient. Node.js' package ecosystem, npm, is the largest ecosystem of open source libraries in the world. We will be making use of npm along with Yeoman and Gulp to package and deploy modules.
As the first step we will install NodeJS Long Term Support Version (LTS). We can install Node JS from this link .
Once we have downloaded the LTS version, run the executable file and proceed.
Accept the license agreement and click on Next.
We will select Node.js run time installation.
Click on Install to start the installation procedure.
Finally we are done installing NodeJS.
Click on Finish button and restart your computer. You won’t be able to run Node.js until you restart your computer.
If we run the NodeJS command prompt, we will get the message as shown below. Thus, the Node JS has been successfully installed in the local machine.
Now, let’s see the version of Node Package Manager (npm) by running the command npm –v . It is running V3 version.
Install Yeoman and Gulp
Yeoman is a scaffolding tool for modern web apps. It helps you to kick-start new projects, prescribing best practices and tools to help you stay productive. Often called Yo, it scaffolds out a new application, writing your build configuration (e.g Gulpfile) and pulling in relevant build tasks and package manager dependencies (e.g npm) that you might need for your build.
Gulp is a JavaScript task runner that helps us automate common tasks like refreshing your browser when you save a file, Bundling and minifying libraries and CSS, Copying modified files to an output directory etc. We will be using Yo and Gulp together for creating SharePoint Client Webparts.
Now, let’s install Yeoman and Gulp simultaneously by running the below command:
npm install -g yo gulp
We can get the version of Yeoman using the command:
yo --version
We can get the Gulp Version using the command:
gulp –v
Install Yeoman SharePoint Generator
The Yeoman SharePoint web part generator helps you to quickly create a SharePoint client-side solution project with the right tool chain and project structure.
Yeoman SharePoint Generator can be installed using the below command:
npm install -g @microsoft/generator-sharepoint
We can get the version of Yeoman Generator by running the below command. As we can see the version is 1.3.2 .
npm view @microsoft/generator-sharepoint version
Code Editor
Next, we need a code editor that will help us with code editing. We can use any code editor or IDE that supports client-side development to build our web part, such as:
- Visual Studio Code
- Atom
- Webstorm
We will use Visual Studio Code in this walkthrough. You can get it from here .
Once we have downloaded the exe, proceed with the installation.
Click on Install to start the installation procedure.
Finally, we have completed installation of the Visual Studio Code editor.
Additional Tools for Development and Debugging
Once we start the development, we will have to debug or test the application. Fiddler and Postman can help us in this task.
Fiddler
Fiddler is an HTTP debugging proxy server application. It captures HTTP and HTTPS traffic and logs it for the user to review. You can get fiddler from here
Once the executable has been downloaded. Click on Install to set up Fiddler in your local machine.
Using fiddler, we can examine the traffic as it is being sent or received.
Postman
Postman can be used to test SharePoint’s REST service endpoints and verify the returned data and request headers. We can get Postman from here
Postman can be added to Chrome as an app.
The REST url can be entered in the Request URL field and we can click on Send to get the SharePoint data.
Thus, we saw how to set up the environment in SharePoint Server 2016 and now we are ready to get started with the new SharePoint Framework development model.
Create the First Hello World SPFx Web part in SP2016
In this section, we will see how to create and deploy the first client web part using SharePoint Framework to understand the project structure and testing procedure.
Create the Web part project
Spin up Node.js command prompt using which we will be creating the web part project structure.
We can create the directory where we would be adding the solution using the below command:
md ClientWebPart-HelloWorld
Let’s move to the newly created working directory using the command:
cd ClientWebPart-HelloWorld
We will then create the client web part by running the Yeoman SharePoint Generator:
yo @microsoft/sharepoint
This will display the prompt which we will have to fill up so as to proceed with project creation,
What is your solution name? : Accept the default client-web-part-hello-world as your solution name and choose Enter.
Where do you want to place your files : Use Current Folder
What framework would you like to start with : Select “No javaScript web framework” for the time being as this is a sample web part
- What is your webpart name : Go on and press enter to accept the default Web part name as HelloWorld
- Go on and press enter to accept the default Web part description as HelloWorld description
Yeoman has started working on the scaffolding of the project. It will install the required dependencies and scaffold the solution files for the HelloWorld web part which will take some time to complete. Once completed, we will get a Congratulations message.
Test the web part
So as to test the client web part, we can build and run it on the local web server where we are developing the web part. SharePoint Framework development uses HTTPS endpoint by default. Since a default certificate is not configured for the local development environment, our browser will report a certificate error. The SharePoint Framework tool chain comes with a developer certificate that we can install for testing client web parts locally. From the current web part directory, run the below command:
gulp trust-dev-cert
Click on Yes to install the certificate.
Now, let’s preview the web part by running the gulp serve command. This command will execute a series of gulp tasks and will create a Node-based HTTPS server at 'localhost:4321'. It will then open the browser and display the client web part.
SharePoint Workbench
SharePoint Workbench is a developer design surface that enables us to test the developed client web parts without deploying them directly to SharePoint. It provides a client-side page to which we can add the created web parts.
Thus the SharePoint Workbench has opened up in the browser but there are no visible web parts. So let’s go ahead and click on the Plus sign.
It will give us the option to add the Hello World web part that we have created recently.On clicking it, the web part will be added to the page. The web part contains few custom messages.
Add the web part to SharePoint
So far we were testing the web part in SharePoint Workbench locally, now let’s try to test it within the SharePoint Context. SharePoint Workbench is also hosted in SharePoint Online to preview the web part. It can be accessed by adding ‘ _layouts/15/workbench.aspx’ to the SharePoint Online URL.
Expand the Plus sign and add the Hello World web part.
The web part has triggered the alert message in the page indicating successful hosting of the web part within SharePoint.
Thus, we saw how to create a client web part using SharePoint Framework and test it within SharePoint.
Create SharePoint Framework Client Web Part to Retrieve and Display List Items
In this section, we will be creating a client Web part, which will be retrieving the list items from SharePoint List (EmployeeList) and will display it in the tabular form in the client Web part, as shown below.
Create the Web part Project
Spin up Node.js command prompt, using which we will be creating the Web part project structure.
This will open up the console where we can create the SharePoint Framework project structure.We can create the directory, where we will be adding the solution, using the command given below.
md GetSharePointListItems
Let’s move to the newly created working directory, using the command.
cd GetSharePointListItems
We will then create the client Web part by running the Yeoman SharePoint Generator.
yo @microsoft/sharepoint
This will display the prompt, which we will have to fill up, so as to proceed with the project creation.
- What is your solution name? : Set it to ‘GetSPListItems’.
On pressing enter, we will be asked to chose the working folder for the project.
- Where do you want to place your files- Use current folder.
- What framework would you like to start with- Select “No javaScript web framework” for the time being, as this is a sample Web part.
- What is your Webpart name- We will specify it as ‘GetSPListItems’ and press Enter
- What is your Webpart description- We will specify it as this Webpart will retrieve the list items from SharePoint list and display in a table.
Yeoman has started working on the scaffolding of the project. It will install the required dependencies and scaffold the solution files for the ‘GetListItems’ Web part, which will take some time to complete. Once completed, we will get a congratulations message.
Edit the web part
Now let’s try to edit the web part and add more functionality to it. To do that navigate to “src\webparts\getSpListItems” location.
In the left pane of Visual Studio Code, we can see the project structure. The bulk of the logic resides within the GetSPListItemsWebPart.ts file. Let’s add the code to retrieve SharePoint list items from the Employee List within this TypeScript file.
Define List Model
Since we want to retrieve an Employee list items data, we will be creating list model with SharePoint list fields in the GetListItemsWebPart.TS file, as shown below. Place it above the ‘GetSpListItemsWebPart’ class.
export interface ISPLists {
value: ISPList[];
}
export interface ISPList {
EmployeeId: string;
EmployeeName: string;
Experience: string;
Location: string;
}
Create Mock HTTPClient to test data locally
In order to test the list item retrieval in the local workbench, we will create a mock store, which returns mock Employee list data. We will create a new file inside ‘src\webparts\ getSpListItems’ folder named MockHttpClient.ts, as shown below.
We will then copy the code given below into MockHttpClient.ts, as shown below.
import { ISPList } from './GetSpListItemsWebPart';
export default class MockHttpClient {
private static _items: ISPList[] = [{ EmployeeId: 'E123', EmployeeName: 'John', Experience: 'SharePoint',Location:'India' },];
public static get(restUrl: string, options?: any): Promise<ISPList[]> {
return new Promise<ISPList[]>((resolve) => {
resolve(MockHttpClient._items);
});
}
}
We can now use the MockHttpClient class in the ‘GetSPListItems’ class. Let’s import the ‘MockHttpClient’ module by going to the GetSpLitItemsWebPart.ts and pasting the line given below just after “import { IGetSpListItemsWebPartProps } from './IGetSpListItemsWebPartProps';”
import MockHttpClient from './MockHttpClient';
We will also add the mock list item retrieval method within the ‘GetSpListItemsWebPart’ class.
private _getMockListData(): Promise<ISPLists> {
return MockHttpClient.get(this.context.pageContext.web.absoluteUrl).then(() => {
const listData: ISPLists = {
value:
[
{ EmployeeId: 'E123', EmployeeName: 'John', Experience: 'SharePoint',Location: 'India' },
{ EmployeeId: 'E567', EmployeeName: 'Martin', Experience: '.NET',Location: 'Qatar' },
{ EmployeeId: 'E367', EmployeeName: 'Luke', Experience: 'JAVA',Location: 'UK' }
]
};
return listData;
}) as Promise<ISPLists>;
}
Retrieve SharePoint List Items
SharePoint Framework has the helper class spHttpClient, which can be utilized to call REST API requests against SharePoint. We will use REST API: “/_api/web/lists/GetByTitle('EmployeeList')/Items” to get the list items from SharePoint List.
To use ‘spHttpClient’, we will first have to import it from the ‘@microsoft/sp-http’ module. We will import this module by placing the line given below after the mockHttpClient import code -“import MockHttpClient from './MockHttpClient';”
import {
SPHttpClient
} from '@microsoft/sp-http';
We will be then adding the method given below to get SharePoint list items, using REST API within the ‘GetSpListItemsWebPart’ class.
private _getListData(): Promise<ISPLists> {
return this.context.spHttpClient.get(this.context.pageContext.web.absoluteUrl + `/_api/web/lists/GetByTitle('EmployeeList')/Items`, SPHttpClient.configurations.v1)
.then((response: Response) => {
debugger;
return response.json();
});
}
Render the SharePoint List Items From Employee List
Once we run the gulp serve command, we can test the Web part in SharePoint Workbench in the local environment or using SharePoint Online Context. SharePoint Framework uses ‘EnvironmentType’ module to identify the environment, where the Web part is executed.
In order to implement this, we will import ‘Environment’ and the ‘EnvironmentType’ modules from the @microsoft/sp-core-library bundle by placing it at the top of the GetSpListItemsWebpart.ts file.
import {
Environment,
EnvironmentType
} from '@microsoft/sp-core-library';
We will then check Environment.type value and if it is equal to Environment.Local, the MockHttpClient method, which returns dummy data which will be called else the method that calls REST API is able to retrieve SharePoint list items will be called.
private _renderListAsync(): void {
if (Environment.type === EnvironmentType.Local) {
this._getMockListData().then((response) => {
this._renderList(response.value);
});
}
else {
this._getListData()
.then((response) => {
this._renderList(response.value);
});
}
}
Finally, we will add the method given below, which will create HTML table out of the retrieved SharePoint list items.
private _renderList(items: ISPList[]): void {
let html: string = '<table class="TFtable" border=1 width=100% style="border-collapse: collapse;">';
html += `<th>EmployeeId</th><th>EmployeeName</th><th>Experience</th><th>Location</th>`;
items.forEach((item: ISPList) => {
html += `
<tr>
<td>${item.EmployeeId}</td>
<td>${item.EmployeeName}</td>
<td>${item.Experience}</td>
<td>${item.Location}</td>
</tr>
`;
});
html += `</table>`;
const listContainer: Element = this.domElement.querySelector('#spListContainer');
listContainer.innerHTML = html;
}
To enable rendering of the list items given above, we will replace Render method in the ‘GetSpListItemsWebPart’ class with the code given below.
public render(): void {
this.domElement.innerHTML = `
<div class="${styles.helloWorld}">
<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" style="font-size:28px">Welcome to SharePoint Framework Development</span>
<p class="ms-font-l ms-fontColor-white" style="text-align: center">Demo : Retrieve Employee Data from SharePoint List</p>
</div>
</div>
<div class="ms-Grid-row ms-bgColor-themeDark ms-fontColor-white ${styles.row}">
<div style="background-color:Black;color:white;text-align: center;font-weight: bold;font-size:18px;">Employee Details</div>
<br>
<div id="spListContainer" />
</div>
</div>
</div>`;
this._renderListAsync();
}
Test the Web part in local SharePoint Workbench
Now, we can see the output generated in the local SharePoint Workbench by running gulp serve.Since the environment is local, the mock data has been used to generate the table, as shown below.
Thus, we have successfully tested the client Web part locally.
Test the Web part in SharePoint Server
Now, let’s test the Web part in SharePoint Workbench available in SharePoint Online. This time, the 'EnvironmentType' check will evaluate to SharePoint and REST API endpoint method will be called to retrieve the list items from SharePoint list. SharePoint Online list EmployeesList to which we are trying to connect, using REST API is given below.
Once we have login in to SharePoint Online, we can invoke the workbench by appending the text ‘_layouts/15/workbench.aspx’ to SharePoint Online URL. As we can see below, the items have been successfully retrieved, using REST API and the data has been built into HTML table in the client Web part.
We can further modify the CSS by making changes in the ‘GetSpListItems.module.scss’ file.
Provision SharePoint Site Columns,Content Type and List using SPFx
In this section, we will see how to provision custom site columns and content type and how to use them while provisioning a custom list.We can create the directory, where we will be adding the solution, using the command given below.
md ProvisionSPList
Let’s move to the newly created working directory, using the command.
cd ProvisionSPList
We will then create the client Web part by running the Yeoman SharePoint Generator.
yo @microsoft/sharepoint
This will display the prompt, which we will have to fill up, so as to proceed with the project creation.
● What is your solution name? : Set it to ‘ProvisionSPList’.
On pressing enter, we will be asked to chose the working folder for the project.
● Where do you want to place your files- Use current folder.
● What framework would you like to start with- Select “No javaScript web framework” for the time being, as this is a sample Web part.
● What is your Webpart name- We will specify it as ‘ProvisionSPList‘ and press Enter
● What is your Webpart description- We will specify it as this Webpart will retrieve the list items from SharePoint list and display in a table.
Yeoman has started working on the scaffolding of the project. It will install the required dependencies and scaffold the solution files for the ‘ProvisionSPList’ Web part, which will take some time to complete. Once completed, we will get a congratulations message.
Edit the web part
Run the Code . to scaffold and open the project in Visual Studio Code.
Now let’s add the folder named ‘Sharepoint’ to maintain the SharePoint files that will be deployed as a package.Within the SharePoint folder let’s add another sub folder named Assets.We will be creating two xml files - elements.xml and schema.xml which will hold the information required to provision the site columns, content type and then use them to create the list. Let’s create the first supporting xml file elements.xml.
Elements.xml file will contain the list information that will be used to provision the list. At first we will be defining the site columns using the ‘Field’ tag and then the content type that will be deployed to the site. We will also be defining the default data that will be provisioned along with the list.
Add the Default data to SharePoint List
We will be adding the default data within the Rows tag as shown below.
Elements.XML
The complete elements.xml that is used with the project is given below :
<?xml version="1.0" encoding="utf-8"?>
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
<Field ID="{11ED4026-1C15-4636-80EF-C27C41DB90E0}"
Name="EmployeeName"
DisplayName="Employee Name"
Type="Text"
Required="FALSE"
Group="Employee" />
<Field ID="{1DA0BA30-F87A-4D1B-9303-729AA02BEE25}"
Name="PreviousCompany"
DisplayName="Previous Company"
Type="Text"
Required="FALSE"
Group="Employee" />
<Field ID="{145B5D00-E3AE-48EB-BB75-9699922AF8D8}"
Name="JoiningDate"
DisplayName="JoiningDate"
Type="DateTime"
Format="DateOnly"
Required="FALSE"
Group="Employee" />
<Field ID="{197F8587-C417-458D-885E-4FBC28D1F612}"
Name="Expertise"
DisplayName="Expertise"
Type="Choice"
Required="FALSE"
Group="Employee">
<CHOICES>
<CHOICE>SharePoint</CHOICE>
<CHOICE>Java</CHOICE>
<CHOICE>.NET</CHOICE>
<CHOICE>Python</CHOICE>
<CHOICE>C++</CHOICE>
<CHOICE>Web Designer</CHOICE>
</CHOICES>
</Field>
<Field ID="{10E72105-7577-4E9E-A758-BBBE8FF4E9BA}"
Name="Experience"
DisplayName="Experience"
Group="Employee"
Type="Number"
Required="False"
Min="0"
Max="30"
Percentage="FALSE">
</Field>
<ContentType ID="0x010100FA0963FA69A646AA916D2E41284FC9D1"
Name="EmployeeContentType"
Group="Employee Content Types"
Description="This is the Content Type for Employee Onboarding">
<FieldRefs>
<FieldRef ID="{11ED4026-1C15-4636-80EF-C27C41DB90E0}" />
<FieldRef ID="{1DA0BA30-F87A-4D1B-9303-729AA02BEE25}" />
<FieldRef ID="{145B5D00-E3AE-48EB-BB75-9699922AF8D8}" />
<FieldRef ID="{197F8587-C417-458D-885E-4FBC28D1F612}" />
<FieldRef ID="{10E72105-7577-4E9E-A758-BBBE8FF4E9BA}" />
</FieldRefs>
</ContentType>
<ListInstance
CustomSchema="schema.xml"
FeatureId="00bfea71-de22-43b2-a848-c05709900100"
Title="Employee"
Description="Employee List created using SharePoint Framework"
TemplateType="100"
Url="Lists/Employee">
<Data>
<Rows>
<Row>
<Field Name="EmployeeName">Priyaranjan</Field>
<Field Name="PreviousCompany">Cognizant</Field>
<Field Name="JoiningDate">10/08/2010</Field>
<Field Name="Expertise">SharePoint</Field>
<Field Name="Experience">7</Field>
</Row>
<Row>
<Field Name="EmployeeName">Nimmy</Field>
<Field Name="PreviousCompany">SunTech</Field>
<Field Name="JoiningDate">11/04/2012</Field>
<Field Name="Expertise">Java</Field>
<Field Name="Experience">4</Field>
</Row>
<Row>
<Field Name="EmployeeName">Jinesh</Field>
<Field Name="PreviousCompany">IBM</Field>
<Field Name="JoiningDate">12/03/2006</Field>
<Field Name="Expertise">.NET</Field>
<Field Name="Experience">11</Field>
</Row>
</Rows>
</Data>
</ListInstance>
</Elements>
Schema.XML
Finally we will be creating the schema.xml file which will contains the list xml. Here, We will be adding the Content Type that we have declared in the elements.xml as below
<ContentTypes>
<ContentTypeRef ID="0x010100FA0963FA69A646AA916D2E41284FC9D9" />
</ContentTypes>
The complete schema.xml will look like below:
<List xmlns:ows="Microsoft SharePoint" Title="Basic List" EnableContentTypes="TRUE" FolderCreation="FALSE" Direction="$Resources:Direction;" Url="Lists/Basic List" BaseType="0" xmlns="http://schemas.microsoft.com/sharepoint/">
<MetaData>
<ContentTypes>
<ContentTypeRef ID="0x010100FA0963FA69A646AA916D2E41284FC9D1" />
</ContentTypes>
<Fields></Fields>
<Views>
<View BaseViewID="1" Type="HTML" WebPartZoneID="Main" DisplayName="$Resources:core,objectiv_schema_mwsidcamlidC24;" DefaultView="TRUE" MobileView="TRUE" MobileDefaultView="TRUE" SetupPath="pages\viewpage.aspx" ImageUrl="/_layouts/images/generic.png" Url="AllItems.aspx">
<XslLink Default="TRUE">main.xsl</XslLink>
<JSLink>clienttemplates.js</JSLink>
<RowLimit Paged="TRUE">30</RowLimit>
<Toolbar Type="Standard" />
<ViewFields>
<FieldRef Name="LinkTitle"></FieldRef>
<FieldRef Name="EmployeeName"></FieldRef>
<FieldRef Name="PreviousCompany"></FieldRef>
<FieldRef Name="JoiningDate"></FieldRef>
<FieldRef Name="Expertise"></FieldRef>
<FieldRef Name="Experience"></FieldRef>
</ViewFields>
<Query>
<OrderBy>
<FieldRef Name="ID" />
</OrderBy>
</Query>
</View>
</Views>
<Forms>
<Form Type="DisplayForm" Url="DispForm.aspx" SetupPath="pages\form.aspx" WebPartZoneID="Main" />
<Form Type="EditForm" Url="EditForm.aspx" SetupPath="pages\form.aspx" WebPartZoneID="Main" />
<Form Type="NewForm" Url="NewForm.aspx" SetupPath="pages\form.aspx" WebPartZoneID="Main" />
</Forms>
</MetaData>
</List>
Before we can deploy the package we have to update the feature in the package-solution.json file
Update Package-Solution.json
Initially the file contents will contain only the solution name. We will have to add the feature node as well to this file.Add the below content after the version tag. Here the id is a Visual studio created GUID that identifies a unique feature.
The contents of the package-solution.json will look like below :
{
"solution": {
"name": "provision-sp-list-client-side-solution",
"id": "f26589ce-0cd0-49c4-9ca3-f4a559851a0d",
"version": "1.0.0.0",
"features": [{
"title": "provision-sp-list-client-side-solution",
"description": "provision-sp-list-client-side-solution",
"id": "7BC1C758-F2A2-4775-B26E-DC60F8620E9A",
"version": "2.0.0.0",
"assets": {
"elementManifests": [
"elements.xml"
],
"elementFiles":[
"schema.xml"
]
}
}]
},
"paths": {
"zippedPackage": "solution/provision-sp-list.sppkg"
}
}
Now lets package the solution using gulp bundle
Package and Deploy the Solution
Now we have to package and bundle the solution using
gulp bundle
gulp package-solution
Thus we are done with the packaging of the solution.If we head over to the solutions folder we can see the ‘provision-sp-list package’ which we will be uploading to SharePoint.
Make a note of the solution URL in the local computer as we will need it to upload to SharePoint.Let’s head over to the SharePoint App Catalog site to where we will be uploading the solution.
Click on Upload to add the solution file to the site.Click on OK to complete the upload.It will ask to trust and Deploy the solution to SharePoint.
We can see the uploaded solution in the App Catalog.Now lets head over to the site contents and add the solution to the site.On searching for the deployed app, it will list out the recently added solution.
Click on it to add the solution to the site.After few seconds we can see the newly created custom site.Now if we head over to the Site Content Types, we can see the newly added site columns and Employee Content Type
Similarly we can see the deployed list along with the site columns and default data from site contents, as shown below :
Retrieve SharePoint Server 2016 User Profile Properties using SPFx and PnP JS
In this section we will see another example of SPFx and PnP in action, here we will be using this combo to retrieve the user profile properties and display them in the webpart .
Create the Web part Project
Spin up Node.js command prompt, using which we will be creating the Web part project structure.
We can create the directory, where we will be adding the solution, using the command given below.
md GetUserProfileProperties
Let’s move to the newly created working directory, using the command.
cd GetUserProfileProperties
We will then create the client Web part by running the Yeoman SharePoint Generator.
yo @microsoft/sharepoint
This will display the prompt, which we will have to fill up, so as to proceed with the project creation.
● What is your solution name? : Set it to ‘GetUserProfileProperties’.
On pressing enter, we will be asked to chose the working folder for the project.
● Where do you want to place your files- Use current folder.
● What framework would you like to start with- Select “No javaScript web framework” for the time being, as this is a sample Web part.
● What is your Webpart name- We will specify it as ‘GetUserProfileProperties’ and press Enter
● What is your Webpart description- We will specify it as ‘Retrieve User Properties using SharePoint Framework’.
Edit the web part
Run Code . to open the project in Visual Studio Code
The project structure will look like below :
Now we have to load PnP JS file which we will use within the project to create list.We will be using npm to add PnP JS file as shown below:
npm install sp-pnp-js --save
Retrieve User Profile data
In order to use PnP methods,we can refer the PnP file in the project as below :
import * as pnp from 'sp-pnp-js';
We will then make use of the below function to fetch the user profile properties of the user and display it within the web part. pnp.sp.profiles.myProperties.get() will return the current user’s profile properties which can be iterated to return the required information.
private GetUserProperties(): void {
pnp.sp.profiles.myProperties.get().then(function(result) {
var userProperties = result.UserProfileProperties;
var userPropertyValues = "";
userProperties.forEach(function(property) {
userPropertyValues += property.Key + " - " + property.Value + "<br/>";
});
document.getElementById("spUserProfileProperties").innerHTML = userPropertyValues;
}).catch(function(error) {
console.log("Error: " + error);
});
}
TS File content to retrieve User Profile Data
The entire TS file contents is as shown below. this.GetUserProperties() in the render method will call the function that will call the function that gets the User Profile properties of the user. It will be then displayed within the div element declared in the render method.
import * as pnp from 'sp-pnp-js';
import { Version } from '@microsoft/sp-core-library';
import {
BaseClientSideWebPart,
IPropertyPaneConfiguration,
PropertyPaneTextField
} from '@microsoft/sp-webpart-base';
import { escape } from '@microsoft/sp-lodash-subset';
import styles from './GetUserProfileProperties.module.scss';
import * as strings from 'getUserProfilePropertiesStrings';
import { IGetUserProfilePropertiesWebPartProps } from './IGetUserProfilePropertiesWebPartProps';
export default class GetUserProfilePropertiesWebPart extends BaseClientSideWebPart<IGetUserProfilePropertiesWebPartProps> {
private GetUserProperties(): void {
pnp.sp.profiles.myProperties.get().then(function(result) {
var userProperties = result.UserProfileProperties;
var userPropertyValues = "";
userProperties.forEach(function(property) {
userPropertyValues += property.Key + " - " + property.Value + "<br/>";
});
document.getElementById("spUserProfileProperties").innerHTML = userPropertyValues;
}).catch(function(error) {
console.log("Error: " + error);
});
}
public render(): void {
this.domElement.innerHTML = `
<div class="${styles.helloWorld}">
<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" style="font-size:28px">Welcome to SharePoint Framework Development using PnP JS Library</span>
<p class="ms-font-l ms-fontColor-white" style="text-align: left">Demo : Retrieve User Profile Properties</p>
</div>
</div>
<div class="ms-Grid-row ms-bgColor-themeDark ms-fontColor-white ${styles.row}">
<div style="background-color:Black;color:white;text-align: center;font-weight: bold;font-size:18px;">User Profile Details</div>
<br>
<div id="spUserProfileProperties" />
</div>
</div>
</div>`;
this.GetUserProperties();
}
protected get dataVersion(): Version {
return Version.parse('1.0');
}
protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration {
return {
pages: [
{
header: {
description: strings.PropertyPaneDescription
},
groups: [
{
groupName: strings.BasicGroupName,
groupFields: [
PropertyPaneTextField('description', {
label: strings.DescriptionFieldLabel
})
]
}
]
}
]
};
}
}
Test the Web part in SharePoint Server
Now, let’s test the Web part in SharePoint Workbench available in SharePoint Online. Once we have login in to SharePoint Online, we can invoke the workbench by appending the text ‘_layouts/15/workbench.aspx’ to SharePoint Online URL. Add the webpart to the page by selecting GetUserProfile icon.
This will add the web part to the page and it will fetch the user profile details of the user and display it.
Implement SharePoint Server 2016 List item CRUD using SPFx and PnP JS
In this section we will see how to create a webpart that does Create/Read/Updated/Delete operations against SharePoint List items using SPFx and PnP JS
Create the Web part Project
Spin up Node.js command prompt, using which we will be creating the Web part project structure.We can create the directory, where we will be adding the solution, using the command given below.
md PnPSPCRUD
Let’s move to the newly created working directory, using the command.
cd PnPSPCRUD
We will then create the client Web part by running the Yeoman SharePoint Generator.
yo @microsoft/sharepoint
This will display the prompt, which we will have to fill up, so as to proceed with the project creation.
● What is your solution name? : Set it to ‘PnPSPCRUD’.
On pressing enter, we will be asked to chose the working folder for the project.
● Where do you want to place your files- Use current folder.
● What framework would you like to start with- Select “No javaScript web framework” for the time being, as this is a sample Web part.
● What is your Webpart name- We will specify it as ‘PnPSPCRUD’ and press Enter
● What is your Webpart description- We will specify it as this Webpart will perform CRUD operations using PnP and SPFx
Edit the Web Part
Run Code . to create the scaffolding and open the project in Visual Studio Code.Now we have to load PnP JS file which we will use within the project to create list.
We will be using npm to add PnP JS file.
npm install sp-pnp-js --save
Implement CRUD using PnP JS
In order to use PnP methods,we can refer the PnP file in the project as below :
import * as pnp from 'sp-pnp-js';
We will then add CRUD buttons in the render method so that the UI looks as below.
Each button will have an event listen which will be invoked on button click.
<button id="AddItem" type="submit" >Add</button>
<button id="UpdateItem" type="submit" >Update</button>
<button id="DeleteItem" type="submit" >Delete</button>
The event listeners will be added as :
private AddEventListeners() : void{
document.getElementById('AddItem').addEventListener('click',()=>this.AddItem());
document.getElementById('UpdateItem').addEventListener('click',()=>this.UpdateItem());
document.getElementById('DeleteItem').addEventListener('click',()=>this.DeleteItem());
}
Each of these methods will use PnP to implement the CRUD operations as :
AddItem()
{
pnp.sp.web.lists.getByTitle('EmployeeList').items.add({
EmployeeName : document.getElementById('EmployeeName')["value"],
Experience : document.getElementById('Experience')["value"],
Location:document.getElementById('Location')["value"]
});
alert("Record with Employee Name : "+ document.getElementById('EmployeeName')["value"] + " Added !");
}
UpdateItem()
{
var id = document.getElementById('EmployeeId')["value"];
pnp.sp.web.lists.getByTitle("EmployeeList").items.getById(id).update({
EmployeeName : document.getElementById('EmployeeName')["value"],
Experience : document.getElementById('Experience')["value"],
Location:document.getElementById('Location')["value"]
});
alert("Record with Employee Name : "+ document.getElementById('EmployeeName')["value"] + " Updated !");
}
DeleteItem()
{
pnp.sp.web.lists.getByTitle("EmployeeList").items.getById(document.getElementById('EmployeeId')["value"]).delete();
alert("Record with Employee ID : "+ document.getElementById('EmployeeId')["value"] + " Deleted !");
}
TS File contents for implementing CRUD using PnP
The entire TS file contents is as shown below,
this.getListData();
this.AddEventListeners();
in the render method will first call the function that will retrieve the list items and display within the div element declared in the render method. AddEventListeners will bind the button events to respective functions which gets called upon the button clicks.
import pnp from 'sp-pnp-js';
import { Version } from '@microsoft/sp-core-library';
import {
BaseClientSideWebPart,
IPropertyPaneConfiguration,
PropertyPaneTextField
} from '@microsoft/sp-webpart-base';
import { escape } from '@microsoft/sp-lodash-subset';
import styles from './PnPspCrud.module.scss';
import * as strings from 'pnPspCrudStrings';
import { IPnPspCrudWebPartProps } from './IPnPspCrudWebPartProps';
export interface ISPList {
ID: string;
EmployeeName: string;
Experience: string;
Location: string;
}
export default class PnPspCrudWebPart extends BaseClientSideWebPart<IPnPspCrudWebPartProps> {
private AddEventListeners() : void{
document.getElementById('AddItem').addEventListener('click',()=>this.AddItem());
document.getElementById('UpdateItem').addEventListener('click',()=>this.UpdateItem());
document.getElementById('DeleteItem').addEventListener('click',()=>this.DeleteItem());
}
private _getListData(): Promise<ISPList[]> {
return pnp.sp.web.lists.getByTitle("EmployeeList").items.get().then((response) => {
return response;
});
}
private getListData(): void {
this._getListData()
.then((response) => {
this._renderList(response);
});
}
private _renderList(items: ISPList[]): void {
let html: string = '<table class="TFtable" border=1 width=100% style="border-collapse: collapse;">';
html += `<th>EmployeeId</th><th>EmployeeName</th><th>Experience</th><th>Location</th>`;
items.forEach((item: ISPList) => {
html += `
<tr>
<td>${item.ID}</td>
<td>${item.EmployeeName}</td>
<td>${item.Experience}</td>
<td>${item.Location}</td>
</tr>
`;
});
html += `</table>`;
const listContainer: Element = this.domElement.querySelector('#spGetListItems');
listContainer.innerHTML = html;
}
public render(): void {
this.domElement.innerHTML = `
<div class="parentContainer" style="background-color: lightgrey">
<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" style="font-size:28px">Welcome to SharePoint Framework Development using PnP JS Library</span>
<p class="ms-font-l ms-fontColor-white" style="text-align: left">Demo : SharePoint List CRUD using PnP JS and SPFx</p>
</div>
</div>
<div class="ms-Grid-row ms-bgColor-themeDark ms-fontColor-white ${styles.row}">
<div style="background-color:Black;color:white;text-align: center;font-weight: bold;font-size:18px;">Employee Details</div>
</div>
<div style="background-color: lightgrey" >
<form >
<br>
<div data-role="header">
<h3>Add SharePoint List Items</h3>
</div>
<div data-role="main" class="ui-content">
<div >
<input id="EmployeeName" placeholder="EmployeeName" />
<input id="Experience" placeholder="Experience" />
<input id="Location" placeholder="Location" />
</div>
<div></br></div>
<div >
<button id="AddItem" type="submit" >Add</button>
</div>
</div>
<div data-role="header">
<h3>Update/Delete SharePoint List Items</h3>
</div>
<div data-role="main" class="ui-content">
<div >
<input id="EmployeeId" placeholder="EmployeeId" />
</div>
<div></br></div>
<div >
<button id="UpdateItem" type="submit" >Update</button>
<button id="DeleteItem" type="submit" >Delete</button>
</div>
</div>
</form>
</div>
<br>
<div style="background-color: lightgrey" id="spGetListItems" />
</div>
`;
this.getListData();
this.AddEventListeners();
}
AddItem()
{
pnp.sp.web.lists.getByTitle('EmployeeList').items.add({
EmployeeName : document.getElementById('EmployeeName')["value"],
Experience : document.getElementById('Experience')["value"],
Location:document.getElementById('Location')["value"]
});
alert("Record with Employee Name : "+ document.getElementById('EmployeeName')["value"] + " Added !");
}
UpdateItem()
{
var id = document.getElementById('EmployeeId')["value"];
pnp.sp.web.lists.getByTitle("EmployeeList").items.getById(id).update({
EmployeeName : document.getElementById('EmployeeName')["value"],
Experience : document.getElementById('Experience')["value"],
Location:document.getElementById('Location')["value"]
});
alert("Record with Employee Name : "+ document.getElementById('EmployeeName')["value"] + " Updated !");
}
DeleteItem()
{
pnp.sp.web.lists.getByTitle("EmployeeList").items.getById(document.getElementById('EmployeeId')["value"]).delete();
alert("Record with Employee ID : "+ document.getElementById('EmployeeId')["value"] + " Deleted !");
}
protected get dataVersion(): Version {
return Version.parse('1.0');
}
protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration {
return {
pages: [
{
header: {
description: strings.PropertyPaneDescription
},
groups: [
{
groupName: strings.BasicGroupName,
groupFields: [
PropertyPaneTextField('description', {
label: strings.DescriptionFieldLabel
})
]
}
]
}
]
};
}
}
Test the Web part in SharePoint Server
Now, let’s test the Web part in SharePoint Workbench available in SharePoint Server 2016. Run Gulp Serve in the Node Command line and head over to SharePoint Server Site. Once we have login in to SharePoint Online, we can invoke the workbench by appending the text ‘_layouts/15/workbench.aspx’ to SharePoint Server URL. Add the webpart to the page by selecting ‘PnPspCRUD’ icon.
The UI will look like below :
Add Item
We can input the details and save it to the list by clicking on Add which will create a new list item using the PnP Add method.On Clicking on Add, The new item has been added to the SharePoint List.
Update Item
Similarly we can update the existing list item by adding the data and providing the list item id which will be used to pick the item from the list and update it.On Clicking on Update, the list item has been updated.
Delete item
We can make use of the PnP delete method to delete the item from the list by providing the item id as shown below.
Summary
Thus we saw how to install Feature Pack 2 for SharePoint Server 2016 and create SharePoint Framework web parts for SharePoint Server 2016
See Also
- SharePoint Framework Development in SharePoint Online
- SharePoint Framework Development E-Book for SharePoint Online
- SharePoint Framework Development Environment Preparation
- Feature Pack 2 for SharePoint 2016
References
- Overview of SharePoint Framework
- SharePoint Build Versions Explained
- Ocober 2017 CU for SharePoint 2016