ASP.NET MVC: DataSource на JavaScript для работы с Web API или снова про JsSite
Сайтостроение | создано: 13.07.2013 | опубликовано: 14.07.2013 | обновлено: 07.02.2024 | просмотров: 7637
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 связку. К обеим частям прилагаются проект для экспериментов.