This is the second article of the series on Angular 2 SharePoint Single Page App with Webpack. In this article we can see how to perform CRUD operation in a SharePoint Single Page App with Angular2 and SP PnP Js Core.
All article is this series
1. Environment setup and solution structure for Angular 2 Single Page App for SharePoint Online
3. Angular2 routing inside SharePoint SitePages Document Library – SP Ng2 SPA Part 3
4. Configuring webpack for development and production build in SharePoint On-line Angular2 SPA – SP Ng2 SPA Part 4
5. Practical difficulties and lessons learnt on Single Page App for SharePoint Online with Angular2 and Typescript – SP Ng2 SPA Part 5
Add a reference to “sp-pnp-js” ( added via package.json) in vendor.browser.ts so that pnp js library would be included as part of the build. Reference to “rxjs” can be removed from this project as “SP PnP Core Js” relies on regular promise based http requests at this time of writing. Removing this file would reduce the file size of “vendor.[hash].js” in production build.
Data Source
The next step is to prepare the data source. Create a list named “Employee” with fields “Title”, “Location”,”Designation”,”Email”. Once the list is created, add an entity object to the project so that it can be used as the medium for data communication. The below is the structure of entity object.
export interface IEmployeeEntity {
Id: number;
Title: string;
Location: string;
Designation: string;
Email: string;
}
Manually creating this object ( interface) may be painful and time consuming. But there are easy options to automatically create this file. Add a record to the list and access it via REST API. Copy the generated JSON object and convert it into Typescript objects from http://json2ts.com/
Interface
The next step is to create an interface named “IEmployee” that would be implemented by other components that needs to interact with the “Employee” object. In this project , “EmployeeAddComponent” and “EmployeeEditComponent” implements this interface.
import { Component, OnInit } from '@angular/core';
import { IEmployeeEntity } from '../shared/app.entities';
export interface IEmployee extends OnInit {
loading: string;
Employee: IEmployeeEntity;
readonly pageTile: string;
readonly pageMode: string;
ngOnInit(): void
saveChanges(): void;
}
CRUD Operation with SP PnP Js Core
Add New Item (Extract from employee.add.component.ts)
saveChanges() {
this.loading = "init";
new sp.Web(AppSettings.SHAREPOINT_SITE_URL).lists.getByTitle("Employee").items.add({
Title: this.Employee.Title,
Location: this.Employee.Location,
Designation: this.Employee.Designation,
Email: this.Employee.Email
}).then((result) => {
this.newEmployee = this.Employee.Title;
this.itemAdded = true;
setTimeout(function () {
this.itemAdded = false;
}.bind(this), 3000);
this.reset();
this.loading = "done";
}).catch((e) => { this.loading = "error"; });
}
View List Data ( All Items) (Extract from home.component.ts)
ngOnInit() {
new pnp.Web(AppSettings.SHAREPOINT_SITE_URL).lists.getByTitle('Employee').items.get().then((result: any) => {
this.Employees = result;
this.loading = "done";
}).catch((e) => { this.loading = "error"; });
}
View , Edit, Delete Single Item
import { Component, OnInit, Input } from '@angular/core';
import { Router, ActivatedRoute } from '@angular/router';
import { AppSettings } from '../../shared/app.settings';
import { IEmployee } from '../../shared/app.interfaces';
import { IEmployeeEntity } from '../../shared/app.entities';
import { AppLoadingComponent } from '../../shared/components/loading/app.loading';
import * as sp from "sp-pnp-js";
@Component({
templateUrl: '../employee.component.html',
})
export class EmployeeEditComponent implements IEmployee {
private Id: string;
@Input()
Employee: IEmployeeEntity = null;
pageTile = "Edit / Delete Employee";
pageMode = "edit";
loading: string = 'init';
constructor(
private appSettings: AppSettings,
private activeRoute: ActivatedRoute,
private router: Router
) { }
ngOnInit() {
this.activeRoute.params.subscribe(params => {
this.Id = params['id'];
new sp.Web(AppSettings.SHAREPOINT_SITE_URL).lists.getByTitle("Employee").items.getById(+this.Id).get().then((result) => {
this.Employee = result;
console.log(this.Employee);
this.loading = "done";
}).catch((e) => { this.loading = "error"; });;
});
}
deleteRecord(event: Event) {
event.preventDefault();
if (confirm('Do you wish to delete this record ?')) {
this.loading = "init";
new sp.Web(AppSettings.SHAREPOINT_SITE_URL).lists.getByTitle("Employee").items.getById(+this.Id).delete().then(() => {
this.loading = "done";
this.router.navigateByUrl('/home');
}).catch((e) => { this.loading = "error"; });
} else {
console.log('no');
}
}
saveChanges() {
this.loading = "init";
new sp.Web(AppSettings.SHAREPOINT_SITE_URL).lists.getByTitle("Employee").items.getById(this.Employee.Id).update({
Title: this.Employee.Title,
Location: this.Employee.Location,
Designation: this.Employee.Designation,
Email: this.Employee.Email
}).then((result) => {
console.log('Record Updated');
this.loading = "done";
this.router.navigateByUrl('/home');
}).catch((e) => { this.loading = "error"; });
}
}
Loading Spinner
import { Component } from '@angular/core';
@Component({
selector: 'app-loading',
template:`
<div>
<div class="app-loading">
<img src="./static/squares.gif" width="60" alt="Loading..."><br> Loading Components...
</div>
</div>`
})
export class AppLoadingComponent { }
If you look at the above code, the variable named “loading” controls the behaviour of the spinner that is displayed during the back end http operations.
Notification
All failed http operations are notified to user via Office UI Fabric’s “Message Bar”. This is created as a component which can be invoked from any page.
import { Component, Input } from '@angular/core';
@Component({
selector: 'app-notify',
template: `
<div>
<div class="ms-MessageBar ms-MessageBar--{{msgType}}">
<div class="ms-MessageBar-content">
<div class="ms-MessageBar-icon">
<i class="ms-Icon ms-Icon--{{msgIcon}}"></i>
</div>
<div class="ms-MessageBar-text">
{{msgText}}
</div>
</div>
</div>
</div>`
})
export class AppNotifyComponent {
@Input() msgText: string = "Error Occurred. Please contact your Administrator !!!";
@Input() msgType: string = "error";
@Input() msgIcon: string = "ErrorBadge";
}
What’s Next
In the next article , routing, app modules and components would be covered
Leave a comment