ASP.NET MVC: DataSource на JavaScript для работы с Web API или снова про JsSite
Сайтостроение | создано: 13.07.2013 | опубликовано: 14.07.2013 | обновлено: 07.02.2024 | просмотров: 7980
Web API очень удобный фрэймворк, который существенно упрощает создание HTTP-сервисов доступных большому число клиентских программ включая браузеры и мобильные устройства. Цель данной статьи описать контрол DataSource, который является JavaScript-оберткой для Web API сервис в концепции ASP.NET MVC.
Описание и предназначение
DataSource – контрол написанный на языке JavaScript. Библиотека JsSite включает в себя, на мой взгляд, полезный js-контрол, который может очень просто отобразить на странице сущности полученные с Web API. При этом разбитие на странице осуществляется автоматически, а также в нем уже присутствует функционал по добавлении, удалению и редактированию сущностей в списке. Помимо того что DataSource “умеет” получать данные постранично, добавлять, удалять, обновлять сущности, еще “умеет” использовать параметризированные запросы к сервису Web API.
Конструктор
DataSource находится в пространстве имен site.controls библиотеки JsSite.
site.controls.DataSource = function (options, queryParams, aggr) {...}
Конструктор принимает по умолчанию следующие параметры:
| Наименование параметра | Тип | Значение |
|---|---|---|
| options | JSON | для расширения или переопределения настроек контрола, которые применяются по умолчанию. См. описание ниже. |
| queryParams | JSON | Универсальный класс параметров запросов. Об этом классе будет рассказано в другой статье. |
| aggr | JSON | Json-объект, который призван пока не используется, но планируется для хранения вычисляемых агрегирующих значений “по столбцам” всего набора данных. Об этом классе будет рассказано в другой статье. |
JSON-объект Options, как параметр настройки DataSource
Опции для настройки контрола DataSource помогут предопределить его поведение, в том числе и заданное по умолчанию.
| Наименование параметра | тип | Значение по умолчанию | Описание |
|---|---|---|---|
| index | number | 0 | Индекс страницы запрашиваемый на сервера. |
| size | number | 10 | Размер страницы (количество возвращаемых объектов) в запросе. |
| groupSize | number | 15 | Количество кнопок страниц в пейджере. |
| service | string | null | JavaScript “обертка” на Web API сервис. Смотри раздел “Сервис для DataSource” |
| items | Array, [] | null | Коллекция объектов, которые требуется разбить на страницы и/или использовать для выборки (select) |
| autoLoad | boolean | true | Запускает получение данных с Web API сразу после инициализации контрола. |
| optionsCaption | JSON | null | Если DataSource используется для связывания с контролом <select>, то это свойство должно задавать объект для первого <option>, которое может быть использовано для выборки объектов с типом nullable. |
| pager | JSON | Объект переопределяет настройки внутреннего контрола для настройки страниц. |
JSON-объект Pager
| Наименование параметра | Тип | Значение по умолчанию | Описание |
|---|---|---|---|
| prev | JSON | { text: “<<”, css: “”} | Текст надписи на кнопке “назад” и CSS стиль для этой кнопки. |
| current | JSON | { css: “active”} | CSS стиль для выбранной кнопки. |
| next | JSON | { text: “<<”, css: “”} | Текст надписи на кнопке “вперед” и CSS стиль для этой кнопки. |
Свойства DataSource
Описание свойств сведу в простую таблицы. Так как контрол продолжает обрастать новыми свойствами, данная таблица будет обновляться.
| Наименование свойства | Тип | Значение по умолчанию | Описание |
|---|---|---|---|
| selectedItems | ko.observableArray | null | Выбранные объекты в наборе полученных данных. На данный момент используется для внутренних расчетов. Планируется реализация множественного выбора. |
| queryParams | JSON | null | Специализированный объект, который является универсальным классом параметров для запроса. Объект содержится в пространстве имен site.controls библиотеки JsSite. |
| execute | JSON | null | Объект для хранения (вызова) методов сервиса используемого в DataSource |
| currentItem | ko.observable | null | Выбранный объект |
| events | JSON | Смотри описание событий ниже. | |
| aggregate | JSON | Зарезервированное свойство для обработки агрегирующих функций. (Реализация запланирована в следующий версии) | |
| indicator | JSON | Объект BusyIndicator из пространства имен site.controls библиотеки JsSite используется для индикации процесса обработки запроса на сервис. | |
| hasPages | boolean | false | После получения набора объектов принимает значение true, если количество страниц больше 1. |
| hasItems | boolean | false | После получения набора объектов принимает значение true, если количество объектов для отображения больше 1. |
| pages | ko.observableArray | null | Страницы сформированные контролом для отображения пейджера. |
| items | ko.observableArray | null | Загруженные объекты |
Методы DataSource
| Наименование метода | Описание |
|---|---|
| resetSelectedItem | Очищает выбранный объект, устанавливая его в значение null. |
| postData | Выполняет отправку данных на сервис Web API используя сервис (site.services.имясущности.js). Тип отправляемого запроса POST. |
| getData | Отправляет запрос на сервер Web API для получения данных. В параметре отправки используется Options. Тип отправляемого запроса GET. |
| putData | Тип отправляемого запроса PUT. |
| delData | Тип отправляемого запроса DELETE. |
| select | Помечает объект в коллекции как “selected”, а также устанавливает свойство “currentItem” этот объект. |
| remove | Удаляет из коллекции выбранный объект (без отправки запроса на сервис Web API) |
| append | Добавляет в коллекцию объект (без отправки запроса на сервис Web API) |
| reload | Перезагружает объект (currentItem) с сервера. Параметром также служить id объекта. |
| clear | Очищает коллекцию объектов |
События Events контрола DataSource
Все события по умолчанию имеют значение null.
| Наименование параметра | Описание |
|---|---|
| selectedHandler | Событие срабатывает после вызова метода select. |
| getCompleteHandler | Событие срабатывает после получение коллекции сущностей. |
| postCompleteHandler | Событие срабатывает после получение положительного результата при добавлении сущности (метод postData). |
| deleteCompleteHandler | Событие срабатывает после получение положительного результата при удалении сущности (метод delData). |
Сервис для DataSource
Для того чтобы DataSource начал работу с Web API требуется наличие специализированного сервиса. Это, своего рода, “обертка” (wrapper) на GET, POST, PUT, DELETE методы Web API. Сервис прост до безобразия, и преследует всего лишь одну цель: все обращения к сервису Web API должны быть из одного места! У вас на представлении (View) может быть несколько DataSource-объектов, которые могут использовать один и тот же сервис. Наверное это всё немного сложно, лучше показать всё на примерах.
Ничего не может быть лучше хорошего примера, чем код сервиса:
(function (site) {
site.services.documents = function () {
var
init = function () {
site.amplify.request.define("getdocument", "ajax", {
url: "/api/documentapi",
dataType: "json",
type: "GET",
cache: false
});
site.amplify.request.define("postdocument", "ajax", {
url: "/api/documentapi",
dataType: "json",
contentType: "application/json; charset=utf-8",
type: "POST",
cache: false
});
site.amplify.request.define("putdocument", "ajax", {
url: "/api/documentapi",
dataType: "json",
contentType: "application/json; charset=utf-8",
type: "PUT",
cache: false
});
site.amplify.request.define("deldocument", "ajax", {
url: "/api/documentapi",
dataType: "json",
contentType: "application/json; charset=utf-8",
type: "DELETE",
cache: false
});
},
mapItem = function (data) {
return new site.m.Document(data);
},
mapItems = function (data) {
var mapped = [];
site._.each(data, function (item) {
mapped.push(mapItem(item));
});
return mapped;
},
getData = function (params, back) {
if (typeof back !== "function") throw new Error("callback not a function");
if (!params) throw new Error("queryParams notis null");
return site.amplify.request({
resourceId: "getdocument",
data: { qp: ko.toJSON(params) },
success: function (json) {
if (json) {
if (json.success) {
params.total(json.total);
var result = mapItems(json.items);
back(result);
return;
}
if (json.warning) {
site.logger.warning(json.warning);
}
if (json.error) {
site.logger.error(json.error);
}
}
back();
},
error: function () {
site.logger.error("Ошибка загрузки сущности \"Документ\");
back();
}
});
},
getDataById = function (params, back) {
if (typeof back !== "function") throw new Error("callback not a function");
if (!params) throw new Error("queryParams notis null");
return site.amplify.request({
resourceId: "getdocument",
data: { id: params },
success: function (json) {
if (json) {
if (json.success) {
var result = mapItem(json.item);
back(result);
return;
}
if (json.warning) {
site.logger.warning(json.warning);
}
if (json.error) {
site.logger.error(json.error);
}
}
back();
},
error: function () {
site.logger.error("Ошибка загрузки сущности \"Должность\");
back();
}
});
},
postData = function (params, back) {
if (typeof back !== "function") throw new Error("callback not a function");
return site.amplify.request({
resourceId: "postdocument",
data: ko.toJSON(params),
success: function (json) {
if (json) {
if (json.success) {
site.logger.success(json.success);
back(new mapItem(json.item));
return;
}
if (json.warning) {
site.logger.warning(json.warning);
}
if (json.error) {
site.logger.error(json.error);
}
}
back();
},
error: function () {
site.logger.error("Ошибка сохранения сущности \"Документ\"");
back();
}
});
},
putData = function (params, back) {
if (typeof back !== "function") throw new Error("callback not a function");
return site.amplify.request({
resourceId: "putdocument",
data: ko.toJSON(params),
success: function (json) {
if (json) {
if (json.success) {
site.logger.success(json.success);
back(new mapItem(json.item));
return;
}
if (json.warning) {
site.logger.warning(json.warning);
}
if (json.error) {
site.logger.error(json.error);
}
}
back();
},
error: function () {
site.logger.error("Ошибка обновления сущности \"Документ\");
back();
}
});
},
delData = function (params, back) {
if (typeof back !== "function") throw new Error("callback not a function");
return site.amplify.request({
resourceId: "deldocument",
data: ko.toJSON(params),
success: function (json) {
if (json) {
if (json.success) {
site.logger.success(json.success);
back(new mapItem(json.item));
return;
}
if (json.warning) {
site.logger.warning(json.warning);
}
if (json.error) {
site.logger.error(json.error);
}
}
back();
},
error: function () {
site.logger.error("Ошибка удаления сущности \"Документ\");
back();
}
});
};
init();
return {
getDataById: getDataById,
postData: postData,
getData: getData,
putData: putData,
delData: delData
};
}();
})(site);
Прошу обратить ваше внимание на то, что у каждого сервиса, который должен быть использован в контроле DataSource должны быть обязательные методы. Все они перечислены в строках 186-190. Дополнительные методы Web API сервиса прописываются аналогичным образом, и так же публикуются в публичные свойства (litteral object). Вызов дополнительных методов производится через объект execute контрола DataSource.
Все сервисы размещены в пространстве имен site.services. Пример сервиса приведен в предыдущем листинге. Но более свежий пример всегда есть в файле site.services.js, который поставляется с nuget-пакетом JsSite.
Ссылки по теме
JsSite – nuget-пакет, в котором находится DataSource-контрол и все необходимые для работы контрола дополнения в виде утилит и вспомогательных классов.
В следующих статьях я, на примере простого приложения, покажу как используя этот незамысловатый контрол можно с легкостью реализовать Master – Details связку. К обеим частям прилагаются проект для экспериментов.