(五)在webpart中實現SharePoint Online的增刪查改(CRUD)操作
在上一篇部落格(四)修改webpart並在SharePoint Online中除錯中,我們在SharePoint Online線上工作臺中使用”this.context.pageContext.web.title“獲取到了當前站點的名稱,下面將介紹如何實現增刪查改操作。微軟提供了一個library pnp-js-core,封裝了REST API,可以使用這個庫來與SharePoint Online互動。
首先開啟powershell進入webpart專案目錄,使用如下npm命令安裝pnp-js-core庫。
npm i --save @pnp/sp @pnp/common @pnp/odata @pnp/logging
安裝完成之後可以在專案的node_modules中看到新新增的庫檔案如下:
新增完成之後,我們需要在webpart中實現以下四個操作:
- 讀取當前站點下的列表
- 在指定列表中建立一個item
- 修改item
- 刪除item
使用Code開啟專案,在HelloWorldWebPart.ts檔案的import程式碼區域新增如下程式碼,引入一個物件:sp
sp物件是對SharePoint REST API的封裝,我們需要使用sp物件與SharePoint Online互動。接下來我們參照上一篇部落格內容在webpart的屬性編輯器中新增一個名字為“列表名稱”的文字框,用於指定需要訪問的列表。還是需要三步,第一步確保import中匯入一個文字框控制元件:
第二步在介面中定義列表名稱屬性:
第三步修改getPropertyPaneConfiguration()方法在webpart屬性編輯器中顯示這個文字框控制元件:
然後新增如下get函式,禁用響應式的屬性編輯功能:
disableReactivePropertyChanges是webpart基類BaseClientSideWebPart的一個屬性,預設是false,也就是使用響應式方式,當用戶修改webpart屬性編輯器中的webpart屬性的時候,webpart會即時根據屬性的值來展示webpart,上一篇部落格中我們為webpart添加了一個背景顏色的屬性,當選擇下拉選單中的顏色的時候,webpart的背景顏色會立即改變。現在將這個屬性值設定為true,webpart屬性編輯器會自動新增一個“應用”的按鈕,對webpart屬性所做的修改,不會立即改變webpart,而是要點選這個按鈕,才會改變webpart。
添加了列表名稱這個屬性之後,webpart的屬性編輯器是這樣子的,注意下方自動添加了一個“應用”按鈕:
添加了這個webpart屬性之後,讓我們新增CRUD操作需要的UI,也就是修改render()方法,新增一些頁面元素,例如文字框和按鈕等待,用於實現CRUD功能。render()方法修改如下:
export default class HelloWorldWebPartWebPart extends BaseClientSideWebPart<IHelloWorldWebPartProps> {
public render(): void {
this.domElement.innerHTML = `
<div class="${ styles.helloWorld }">
<div class="${ styles.container }">
<div class="${ styles.row }" style="background-color:${this.properties.webpartcolor}">
<div class="${ styles.column }">
<span class="${ styles.title }">Welcome to SharePoint!</span>
<p class="${ styles.subTitle }">Customize SharePoint experiences using Web Parts.</p>
<p class="${ styles.description }">${escape(this.properties.description)}</p>
<p class="${ styles.description }">當前站點名字:${escape(this.context.pageContext.web.title)}</p>
<div class="${ styles.row }">
<button class="${styles.button}" id="showListButton"><span>顯示list</span></button>
</div>
<div class="${ styles.row }">
<button class="${styles.button}" id="showItemButton"><span>顯示item</span></button>
</div>
<div class="${ styles.row }">
<span class="${styles.title}">輸入標題:</span>
<input type="text" id="titleTxtCreate"/>
<button class="${styles.button}" id="createButton"><span>新建item</span></button>
</div>
<div class="${ styles.row }">
<span class="${styles.title}">輸入ID:</span>
<input type="text" id="idTxtUpdate"/>
<button class="${styles.button}" id="updateButton"><span>更新item</span></button>
</div>
<div class="${ styles.row }">
<span class="${styles.title}">輸入ID:</span>
<input type="text" id="idTxtDelete"/>
<button class="${styles.button}" id="deleteButton"><span>刪除item</span></button>
</div>
<div class="${ styles.row }">
<span class="${styles.title}">當前狀態:</span>
<span id="message" class="${styles.title}"></span>
</div>
<p id="lists"></p>
<p id="items"></p>
</div>
</div>
</div>
</div>`;
this.bindButtonEvent();
}
一共添加了5個按鈕,第一個“顯示List”按鈕用於顯示當前站點下的列表,第二個“顯示Item”按鈕會根據webpart屬性編輯器中指定的列表名稱,列出列表中的item,其他的按鈕是對item的操作,包括新建/更新/刪除。新增UI之後,webpart變成了下面的樣子:
除了新增新的UI,在render()方法的最後還添加了一個函式this.bindButtonEvent(),這個方法會在新新增的按鈕上繫結onclick事件,函式實現如下:
private bindButtonEvent(){
const webpart:HelloWorldWebPartWebPart = this;
this.domElement.querySelector("#showListButton").addEventListener('click', ()=> {webpart.showAllList();});
this.domElement.querySelector("#showItemButton").addEventListener('click', ()=> {webpart.showItems();});
this.domElement.querySelector("#createButton").addEventListener('click', ()=> {webpart.createNewItem();});
this.domElement.querySelector("#updateButton").addEventListener('click', ()=> {webpart.updateItem();});
this.domElement.querySelector("#deleteButton").addEventListener('click', ()=> {webpart.deleteItem();});
}
在這個方法裡,使用this.domElement.querySelector()方法,根據button的id來獲取頁面上的按鈕,語法與jQuery一樣,然後在button上繫結方法,下面我們依次看一下這幾個方法,首先是showAllList()方法:
private showAllList():void {
const listDom : Element = this.domElement.querySelector("#lists");
sp.web.lists.get().then(lists=>{
listDom.innerHTML += `<ul>${lists.map(l=>`<li>${l.Title}</li>`).join("")}</ul>`;
});
}
這個方法首先使用querySelector查詢ID為lists的頁面元素,然後使用sp.web.lists獲取列表,最後將list列表顯示在webpart上。
第二個方法是showItems(),程式碼如下所示:
private showItems():void{
const itemsDom : Element = this.domElement.querySelector("#items");
if(this.properties.listName != ""){
sp.web.lists.getByTitle(this.properties.listName).items.get().then(items=>{
itemsDom.innerHTML += `<ul>${items.map(i=>`<li>${i.Title}</li>`).join("")}</ul>`;
});
}
else{
itemsDom.innerHTML += "請指定列表";
}
}
首先通過this.properties.listName讀取webpart屬性編輯器中的指定的列表名稱,然後根據列表名稱,獲取列表,然後再獲取列表的items並顯示在webpart上。
第三個方法是createNewItem(),程式碼如下:
private createNewItem():void{
const messageDom = this.domElement.querySelector("#message");
messageDom.innerHTML = "正在建立item...";
const createTitleDom : HTMLInputElement = <HTMLInputElement>this.domElement.querySelector("#titleTxtCreate");
console.log(createTitleDom.value);
let newItemTitle:string = createTitleDom.value;
sp.web.lists.getByTitle(this.properties.listName).items.add({
Title: newItemTitle
}).then(result =>{
result.item.select("id").get().then(d => {messageDom.innerHTML = "item建立成功! item id: " + d.Id});
}).catch(e =>{
messageDom.innerHTML = "建立失敗! 錯誤: " + e.message;
});
}
這個方法需要讀取UI中的文字框的值,所以在使用querySelector查詢文字框textbox的時候,需要將其轉換為一個HTMLInputElement物件才可以使用文字框的value屬性讀取資料。讀取到了資料之後,可以使用console.log方法將資料輸出到瀏覽器的控制檯來檢視。新增一個item使用items集合的add方法,在這個方法的引數中指定item的屬性,這裡我們只指定了標題,返回值是一個Promise物件,如果新增成功,執行then方法,成功的返回值result是ItemAddResult介面,其定義為:
所以我們可以在then方法中讀取到item的ID屬性值。如果新增失敗,會執行catch方法,顯示錯誤資訊。
與新增item的方法類似,更新一個item和刪除一個item的方法如下:
private updateItem():void{
const messageDom = this.domElement.querySelector("#message");
messageDom.innerHTML = "正在更新item...";
const updateIdDom : HTMLInputElement = <HTMLInputElement>this.domElement.querySelector("#idTxtUpdate");
console.log(updateIdDom.value);
let updateItemId:string = updateIdDom.value;
sp.web.lists.getByTitle(this.properties.listName).items.getById(parseInt(updateItemId)).update({
Title: `標題 ${new Date()}`
}).then(result => {
result.item.get().then(d => {messageDom.innerHTML = "item更新成功! item title: " + d.Title});
}).catch(e =>{
messageDom.innerHTML = "更新失敗! 錯誤: " + e.message;
});
}
private deleteItem():void{
const messageDom = this.domElement.querySelector("#message");
messageDom.innerHTML = "正在刪除item...";
const deleteIdDom : HTMLInputElement = <HTMLInputElement>this.domElement.querySelector("#idTxtDelete");
console.log(deleteIdDom.value);
let deleteItemId:string = deleteIdDom.value;
sp.web.lists.getByTitle(this.properties.listName).items.getById(parseInt(deleteItemId)).delete().then(result=>{
messageDom.innerHTML = "刪除成功!";
}).catch(e=>{
messageDom.innerHTML = "刪除失敗! 錯誤: " + e.message;
});
}
為了演示方便,在更新一個item的時候只要指定item的id即可,item的標題會自動更新為“標題”+當前時間。
儲存檔案,確保啟動了gulp serve,開啟線上的workbench工作臺,重新新增webpart,點選“顯示list”按鈕,會發現webpart列出了當前站點下的列表:
其中倒數第二個是我建立的一個custom list,也就是自定義列表,表的結構如下:
下面演示一下如何在這個列表上操作item。首先在webpart屬性編輯器中的列表名稱中填上“自定義列表”,然後點選“應用”按鈕:
點選webpart上的“顯示item”按鈕,webpart會呼叫showItems()方法列出“自定義列表”中的所有item:接下來可以建立一個item,輸入標題,然後點選“新建item”按鈕:
可以看到新的item被成功創建出來,並且顯示新建item的id:
同樣可以嘗試更新item以及刪除item的功能,這裡不在贅述,本文完整程式碼已經上傳到碼雲,下載地址:
https://gitee.com/shrenk/SPFx-webpartcrud.git