いぜん、この辺のポスト
SharePoint2013 & Knockout.js で遊んでみた(その3)
でKnockout.jsを使ってSharePointリストのCRUDを試みましたが、その時心残りだったのが、jQuery Library for SharePoint Web Servicesというライブラリを使っていたこと、アイテム更新時に差分だけの更新ができなかったことでした。
で、かねてよりRESTサービスを使って何とかできないかなぁ・・・と考えていたのですが、先日こちらの記事を読みまして、
SharePoint REST サービスを使用したアイテムの CRUD 方法 – Japan SharePoint Support Team Blog – Site Home – TechNet Blogs
ここに記載のサンプルコードを元にトライしてみることにしました。(SharePoint2013のオンプレ環境です)
画面イメージはこんな感じです。
事前準備として、サイト内に「testList」という名前のカスタムリストを作成し、「Body」という一行テキスト列を追加しておきます。
ではソースコードです。
以下を、ページのスクリプトエディタ内にぺちょっと貼っていただけばOKです。
<script type="text/javascript" src="http://code.jquery.com/jquery-1.11.1.min.js"></script>
<script type="text/javascript" src="http://ajax.aspnetcdn.com/ajax/knockout/knockout-2.2.1.js"></script>
<script langauge="JavaScript">
var weburl = "http://[your host]/[your site]";
var listTitle = "testList";
var myDigest = null;
function ItemsModel() {
var self = this;
self.Items = ko.observableArray([]);
GetItems();
function GetItems() {
$.ajax({
url: weburl + "/_api/Web/Lists/GetByTitle('" + listTitle + "')/Items",
type: "GET",
headers: {
"accept": "application/json;odata=verbose",
"Content-Type": "application/json;odata=verbose",
"x-requestforceauthentication": true
},
success: function(data){
if (data.d.results) {
self.Items(data.d.results);
}
},
error: function (xhr) { alert(xhr.status + ": " + xhr.statusText) }
});
}
function runWithFormDigest(fn){
if (myDigest == null){
$.ajax({
url: weburl + "/_api/contextinfo",
type: "POST",
contentType: "application/x-www-url-encoded",
dataType: "json",
headers: {
"accept": "application/json;odata=verbose",
},
contentLength: 0,
beforeSend: function (xhr) { xhr.withCredentials = true; },
success: function (data) {
if (data.d) {
myDigest = data.d.GetContextWebInformation.FormDigestValue;
fn();
}
}
});
} else {
fn();
}
}
self.AddRow = function() {
self.Items.push({
ID: "New",
Title: "",
Body: "",
});
};
self.DelItem = function(data){
var id = data.ID;
if (id !== "New") {
runWithFormDigest(function(){
$.support.cors = true;
$.ajax({
url: weburl + "/_api/Web/Lists/GetByTitle('" + listTitle + "')/Items(" + id + ")",
type: "POST",
headers: {
"X-HTTP-Method":"DELETE",
"accept": "application/json;odata=verbose",
"Content-Type": "application/json;odata=verbose",
"x-requestforceauthentication": true,
"X-RequestDigest": myDigest,
"IF-MATCH": "*"
},
success: function(xhr){ alert("completed.")},
error: function (xhr) { alert(xhr.status + ": " + xhr.statusText) }
});
});
};
self.Items.remove(data);
};
self.SaveItem = function(data){
var id = data.ID;
var title = data.Title;
var body = data.Body;
if(id!= "New"){
runWithFormDigest(function(){
$.support.cors = true;
$.ajax({
url: weburl + "/_api/Web/Lists/GetByTitle('" + listTitle + "')/Items(" + id + ")",
type: "POST",
data: JSON.stringify({ '__metadata': { 'type': 'SP.Data.TestListListItem' }, 'Title': title, 'Body': body }),
headers: {
"X-HTTP-Method":"MERGE",
"accept": "application/json;odata=verbose",
"Content-Type": "application/json;odata=verbose",
"x-requestforceauthentication": true,
"X-RequestDigest": myDigest,
"IF-MATCH": "*"
},
success: function(xhr){ GetItems(); alert("completed.");},
error: function (xhr) { alert(xhr.status + ": " + xhr.statusText) }
});
});
} else {
runWithFormDigest(function(){
$.support.cors = true;
$.ajax({
url: weburl + "/_api/Web/Lists/GetByTitle('" + listTitle + "')/Items",
type: "POST",
data: JSON.stringify({ '__metadata': { 'type': 'SP.Data.TestListListItem' }, 'Title': title, 'Body': body }),
headers: {
"accept": "application/json;odata=verbose",
"Content-Type": "application/json;odata=verbose",
"x-requestforceauthentication": true,
"X-RequestDigest": myDigest
},
success: function(xhr){ GetItems(); alert("completed.")},
error: function (xhr) { alert(xhr.status + ": " + xhr.statusText) }
});
});
}
}
}
$(document).ready(function () {
ko.applyBindings(new ItemsModel());
});
</script>
<div id="mainContent">
<table>
<thead>
<tr>
<th>ID</th>
<th>Title</th>
<th>Body</th>
<th></th>
<th></th>
</tr>
</thead>
<tbody data-bind='foreach: Items'>
<tr>
<td data-bind="text:ID"></td>
<td><input data-bind='value: Title' /></td>
<td><input data-bind='value: Body' /></td>
<td><input type='button' value='Save' data-bind='click: $root.SaveItem' /></td>
<td><input type='button' value='Delete' data-bind='click: $root.DelItem'/><td>
</tr>
</tbody>
</table>
<input type="button" value="Add New" data-bind='click: AddRow' />
</div>
なお、上で引用したSharePoint Support Teamさんのブログではアイテムの追加と更新のとき、「type」に「SP.ListItem」を渡していましたが、私の環境ではうまくいきませんでした。
なんでだろう・・・と悩みつつ、こちらを読むと
REST を使用したリスト アイテムの操作
この操作を実行するには、リストの ListItemEntityTypeFullName プロパティを知っていて、それを HTTP 要求本文の type の値として渡す必要があります。
とあったので、上記ソースコードのような書き方になっています。
私のソースコードでうまくいかない場合は、Support Teamさんのブログを参照してください。
※ListItemEntityTypeFullName プロパティは、ブラウザのアドレスバーに以下を入力してEnterすると取得できます。
http://[your host]/[your site]/_api/lists/getbytitle('testList')?$select=ListItemEntityTypeFullName
RESTサービスだと値をJSON形式で取れるので、SPServicesを使っていたときよりだいぶシンプルに書けたのではないかと思います。