Понадобилось мне как то раз, сделать порционную загрузку данных на страницу без PostBack запроса, причем с данные должны были браться из списка Sharepoint. Обратившись к великому Google пришел к выводу, что у меня есть только один вариант: REST Interface.
Client Object Model не рассматривался ввиду громоздкости получившегося бы кода.
Для биндинга получаемых данных было решено использовать Angular JS
REST Interface
Сервис доступен сразу, как говориться, из коробки, по адресу http://{siteName}/_vti_bin/ListData.svc. Работает он по протоколу oData(открытый веб-протокол для запроса и обновления данных, который использует в качестве запросов HTTP-команды, и возвращает ответы в форматах Atom, JSON или XML).
Приступим
Тех. задание выглядело следующим образом: «При загрузке страницы отображать n записей из списка, которые соответствуют определенным условиям. При нажатии на кнопку „Получить еще“ догружаются еще n элементов. Если элементы закончились, выводить сообщение об окончании ленты данных».
Для получения информации о списках и типах данных можно использовать запрос http://{siteName}/_vti_bin/ListData.svc/$metadata/
Пишем html каркас
<SharePoint:ScriptLink ID="ScriptLinkAngular" runat="server" Name="SharePointProject/js/angular/angular.js" Localizable="false"/>
<SharePoint:ScriptLink ID="ScriptLinkApp" runat="server" Name="SharePointProject/js/app.js" Localizable="false"/>
<div ng-app="testApp">
<div ng-controller="ListCtrl">
<div ng-repeat="item in JsonItems.items" style="margin-top: 10px;">
<pre> CustomTest: <b>{{item.CustomTest}}</b> <br/> CustomNumber: <b>{{item.CustomNumber}}</b></pre>
</div>
<!-- Показываем ошибки если есть -->
<div ng-show="JsonItems.showError" class="alert alert-danger" >{{JsonItems.error}}</div>
<!-- Сообщение о загрузке -->
<div ng-show="JsonItems.busy" class="alert alert-info" >Loading data...</div>
<!-- Получить еще -->
<div ng-hide="JsonItems.busy" class="alert alert-success" ng-click="JsonItems.nextPage()" > Get more... </div>
</div>
</div>
JavaScript
var testApp = angular.module('testApp', []);
testApp.controller('ListCtrl', ListCtrl);
function ListCtrl($scope, $http, Items) {
$scope.JsonItems= new Items();
$scope.JsonItems.nextPage();
}
testApp.factory('Items', function($http) {
var Items = function() {
this.items = [];
this.busy = false;
this.after = 0;
this.count=25;
this.showError= function () {
return this.error.length>0};
this.error="";
};
Items.prototype.nextPage = function() {
if (this.busy) return;
this.busy = true;
var url = "http://{siteName}/_vti_bin/ListData.svc/Test?$skip=" + this.after + "&$top="+this.count +"&$orderby=CustomNumber&$select=CustomNumber,CustomTest";
$http({method: 'GET', url: url }).success(function(data)
{
var items = data.d;
if (items.length > 0){
for (var i = 0; i < items.length; i++) {
this.items.push(items[i]);
}
else {
this.error = "No more data"
}
this.after += this.count;
this.busy = false;
}
}.bind(this)).
error(function(data, status) {
this.error = "Error: " + data;
this.busy = false;
}.bind(this));
};
return Items;
});
Рассмотрим подробнее строку
var url = "http://{siteName}/_vti_bin/ListData.svc/Test?$skip=" + this.after + "&$top="+this.count +"&$orderby=CustomNumber&$select=CustomNumber,CustomTest";
В данном случае мы получаем от сервиса json, содержащий 2 поля CustomNumber и CustomTest (на самом деле их 3, сервис добавляет еще атрибут __metadataв котором содержится url, тип и etag элемента). Результат состоит из n элементов и отсортирован по столбцу CustomNumber. Если необходимо добавить фильтрацию, то дописываем, например, &$filter=CustomNumber gt 50.
Замечание, если с фильтром не используются параметры $skip или $top, то строку
var items = data.d;
надо заменить на
var items = data.d.results;
Итого
REST Interface обладает довольно гибкой системой фильтрации и позволяет легко составлять сложные запросы.
Из минусов я бы выделил следующее:
- Чувствительность к регистру в названии списков, полей, служебных слов
- Разная возвращаемая структура при разных запросах (в одних случаях возвращается {«d»: {«results»:...}}, в других {«d»: {...}} )
- Возвращает в json Title, вместо InternalName (что очень не удобно при работе с русскими именами)
Хотя минусом можно назвать только последний пункт.
В общем первым впечатлением от REST в Sharepoint я остался доволен.
Автор: noExcept