Blog written by:
Dhaval Shah
SharePoint & .Net Consultant
Intro
In our previous article we showed how to create a simple client-side web part using SharePoint Framework (SPFx). In this article, we add some more features to set up announcements from the SharePoint lists and display them in the web part. When completed successfully, the web part will look something like this.
You can download the entire source code for this article from here
Announcement List
For loading the announcement list in the web part, use the data from the SharePoint OOB announcement list. Make sure the site where you’re deploying the web part has an announcement list, and it has some data added to it.
The announcement list looks like this:
Development of Web Part
Add the announcement class, which you’ll use to store the data available from the SharePoint List. Create an interface for the announcement (IAnnouncement) and an array of announcements (IAnnouncements), as shown below. Create a separate typescript file “Announcement.ts” as also shown below.
You can view the entire code on github repository here.
export interface IAnnouncements{
value: IAnnouncement[];
}
export interface IAnnouncement{
Id:string;
Title:string;
Body:string;
}
Service Layer
You also create your service layer, which fetches the data from the announcement list if you currently have the web part launched in the SharePoint; otherwise, it launches the data from the mock service.
Create an interface for the service ISharedServiceProvider.ts.
import { IAnnouncements } from "../announcement/Announcements";
export interface ISharedServiceProvider {
getAnnouncements(): Promise;
}
Now, create two classes MockServiceProvider and SharedServiceProvider.
MockServiceProvider—This fetches the mock data for the local workbench.
SharedServiceProvider—This fetches the data from the SharePoint List for the SharePoint workbench.
import { ISharedServiceProvider } from './ISharedServiceProvider';
import { IAnnouncement, IAnnouncements } from "../announcement/Announcements";
export class MockServiceProvider implements ISharedServiceProvider {
constructor() {
}
private static mockAnnouncements: IAnnouncement[] = [
{ Title: 'Announcment #1', Body: 'Some Announcment description 1', Id: '1' },
{ Title: 'Announcment #2', Body: 'Some Announcment description 2', Id: '2' },
{ Title: 'Announcment #3', Body: 'Some Announcment description 3', Id: '3' }
];
public getAnnouncements(): Promise {
var announcements: IAnnouncements = { value: MockServiceProvider.mockAnnouncements };
return new Promise((resolve) => {
resolve(announcements);
});
}
}
import { ISharedServiceProvider } from './ISharedServiceProvider';
import { IAnnouncements } from "../announcement/Announcements";
import { SPHttpClient, SPHttpClientResponse } from '@microsoft/sp-http';
import { ServiceKey, ServiceScope } from '@microsoft/sp-core-library';
import { PageContext } from '@microsoft/sp-page-context';
export class SharedServiceProvider implements ISharedServiceProvider {
public static readonly serviceKey: ServiceKey = ServiceKey.create('dps:ISharedServiceProvider', SharedServiceProvider);
private _spHttpClient: SPHttpClient;
private _pageContext: PageContext;
private _currentWebUrl: string;
constructor(serviceScope: ServiceScope) {
serviceScope.whenFinished(() => {
this._spHttpClient = serviceScope.consume(SPHttpClient.serviceKey);
this._pageContext = serviceScope.consume(PageContext.serviceKey);
this._currentWebUrl = this._pageContext.web.absoluteUrl;
});
}
public getAnnouncements(): Promise {
return new Promise((resolve) => {
resolve(this._spHttpClient.get(`${this._currentWebUrl}/_api/lists/GetByTitle('Announcements')/items`, SPHttpClient.configurations.v1)
.then((response: SPHttpClientResponse) => {
return response.json();
}));
});
}
}
Now, go back and design the AnnouncementWebpart.ts,
Initialize the web part with the isDebug property that keeps track of the current environment of the web part. If the current environment type is test or local, fetch the data from the mock service, and if the current environment is SharePoint, fetch the data from the SharePoint.
Initialize the constructor of the web part as follows:
private isDebug: boolean;
public constructor(context: IWebPartContext) {
super();
this.isDebug =
DEBUG && (Environment.type === EnvironmentType.Test || Environment.type === EnvironmentType.Local);
}
In the render() method of the web part, create the web part outer structure of the webpart, and based on the isDebug variable, initialize the service.
public render(): void {
this.domElement.innerHTML = `
<div class="${styles.announcements}">
<header class="${styles.titleblock}">
<h2>${escape(this.properties.description)}</h2>
</header>
<div id="announcementListContainer">
</div>
</div>
</div>`;
// Based on the debug variable initialize the service
this._sharedService = this.isDebug
? new MockServiceProvider()
: this.context.serviceScope.consume(SharedServiceProvider.serviceKey);
this.renderWebpartData();
}
Create a renderWebpartData() method that makes a call to the service initialized earlier and get the data.
private renderWebpartData() {
this._sharedService.getAnnouncements().then((response: IAnnouncements) => {
this.renderHtmlFromData(response.value);
}).catch((err) => {
console.log('Error getting announcements : ' + err);
});
}
renderHtmlFromData() method will iterate through the data obtained and display it as HTML.
private renderHtmlFromData(announcements: IAnnouncement[]): void {
let html: string = '';
//const announcementLogo: any = require('../images/announcement.png');
let announcementLogo: string = String(require('./images/Announcement.png'));
announcements.forEach((item: IAnnouncement) => {
html += `
<ul class="${styles.announcementsList}">
<li>
<div class="${styles.announcementIcon}">
<img src="${announcementLogo}" />
</div>
<div class="${styles.txt}">
<h2>${item.Title}</h2>
<p>${item.Body}</p>
</div>
</li>
</ul>`;
});
const listContainer: Element = this.domElement.querySelector('#announcementListContainer');
listContainer.innerHTML = html;
}
Styling the Web Part
Now, add some css classes in the Announcement.module.scss to use in the web part.
.announcements {
.titleblock {
padding: 15px 17px 18px 1px;
}
.titleblock:before {
width: 338px;
height: 10px;
}
.titleblock h2 {
font-size: 22px;
margin-top: 12px;
color: #435563;
}
.titleblock .btn {
margin: 4px 0 0;
}
.titleblock h2 {
font-size: 22px;
margin-top: 12px;
}
.titleblock h2 {
float: left;
font-size: 20px;
font-weight: 500;
margin-bottom: 0;
line-height: 1.2;
margin: 7px 0 0;
text-transform: uppercase;
width: calc(100% - 100px);
}
.titleblock:before {
top: 0;
left: 0;
content: "";
width: 300px;
height: 10px;
position: absolute;
background-color: #435563;
}
.announcementsList {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-ms-flex-wrap: wrap;
flex-wrap: wrap;
background: #fff;
margin-bottom: 33px;
padding: 26px 15px 1px;
border-bottom: 1px solid #a2a2a2;
list-style: none;
}
.announcementsList li {
display: flex;
margin-bottom: 20px;
padding-bottom: 10px;
}
.announcementIcon {
display: block;
width: 54px;
height: 68px;
padding: 30px 15px;
border-radius: 4px;
text-align: center;
color: #7a8995;
line-height: 1.2;
}
.txt {
padding: 7px 30px 0 23px;
}
}
Once you complete all the steps, you can build your web part using the command below.
Gulp Build
Launch Web Part in Local Workbench
You can test the web part in the local workbench with the mock data using the gulp serve command. It launches the browser, and you can add the announcement web part on the page.
After selecting the web part, it will add the web part, and you can see the mock data on the web part.
Launch a Web Part in SharePoint Workbench
Note: Make sure the gulp serve command is running in the background.
Navigate to the SharePoint Website created in the first article of the series.
https://yoursharepointsite/sites/SPFX/_layouts/15/workbench.aspx
As you did with a local workbench, you have to add the web part on the workbench.
In the next article, you’ll learn how to package the web part and deploy it to the SharePoint. Stay tuned!
- SharePoint Metadata - October 8, 2018
- SharePoint Permission Levels - August 29, 2018
- SharePoint Online User Permission Reports - March 8, 2018
Hi, thanks for the article. I successfully used it as a reference.
Now i would like to abstract the list url from the current web in the constructor of the SharedServiceProvider, but since the service provider is created from the ..serviceScope.consume(SharedServiceProvider.serviceKey) i can’t directly do it (i think).
Is it possible? If yes can you tell how to it?