А что в итоге?
Для того, чтобы сразу же стало понятно, ради чего мы сегодня собрались в этом маленьком блоге, позвольте показать вам видеоролик, который наглядно демонстрирует результат реализации поставленной задачи.
Редактирование комплексных типов при помощи Knockout
В конце статьи вы можете скачать демонстрационный проект и провести свои эксперименты.
Постановка задачи
Есть две сущности “Пользователь” и “Питомец” (Person и Pet). У пользователя может быть один питомец. Требуется возможность выбирать домашнего питомца у пользователя при редактировании. Отображение и подстановка питомца должны быть в виде объекта. Контрол для отображение должен иметь подменяемые шаблоны.
Немного классов на JavaJscript
Если учесть, что сущности имеют зависимость “один-ко-многим”, то классы моделей в JavaScript могут выглядеть таким образом:
1: $(function () { 2: 3: «use strict»; 4: 5: site.m.Pet = function (dto) { 6: var me = this, data = dto || {}; 7: me.id = ko.observable(data.id); 8: me.name = ko.observable(data.name); 9: me.type = ko.observable(data.type); 10: 11: me.selected = ko.observable(false); 12: 13: me.petName = ko.computed(function () { 14: if (me.name && me.type) { 15: return me.type() + ‘ ‘ + me.name(); 16: } 17: return»; 18: }); 19: return me; 20: }; 21: 22: site.m.Person = function (dto) { 23: var me = this, data = dto || {}; 24: me.firstName = ko.observable(data.firstName); 25: me.lastName = ko.observable(data.lastName); 26: me.pet = ko.observable(data.pet); 27: 28: me.selected = ko.observable(false); 29: 30: me.dirtyFlag = new ko.DirtyFlag([ 31: me.firstName, 32: me.lastName 33: ]); 34: return me; 35: }; 36: 37: });
Обратите внимание на строки 11 и 28 – это свойство требуется для контрола DataSource (именно его я и буду использовать). Подробное описание самого контрола, его принципов работы, свойств и методов можно посмотреть в описании (скоро).
А в строках 30-34 я подключил возможность отслеживания состояния полей на предмет изменения. Надеюсь в следующих статьях я затрону и эту тему.
Тестовые данные для классов
Наполнение данных я вынесу в отдельный не только класс, но и в отдельный файл. Наполним наши классы некоторым количеством данных:
1: site.utils.dataPets = [ 2: new site.m.Pet({ ‘id’: 51, ‘name’: ‘Пупсик’, ‘type’: ‘Кот’ }), 3: new site.m.Pet({ ‘id’: 52, ‘name’: ‘Семен’, ‘type’: ‘Конь’ }), 4: new site.m.Pet({ ‘id’: 53, ‘name’: ‘Мурка’, ‘type’: ‘Хорек’ }), 5: new site.m.Pet({ ‘id’: 54, ‘name’: ‘Золотуха’, ‘type’: ‘Рыбка’ }) 6: ]; 7: 8: site.utils.dataPeople = [ 9: new site.m.Person( 10: { 11: ‘firstName’: ‘Иван’, 12: ‘lastName’: ‘Прохоров’, 13: ‘pet’: site.utils.dataPets[2] 14: } 15: ), 16: new site.m.Person( 17: { 18: ‘firstName’: ‘Игорь’, 19: ‘lastName’: ‘Пупкин’, 20: ‘pet’: site.utils.dataPets[1] 21: } 22: ), 23: new site.m.Person( 24: { 25: ‘firstName’: ‘Александр’, 26: ‘lastName’: ‘Болотов’, 27: ‘pet’: site.utils.dataPets[0] 28: } 29: ) 30: ];
Пришло время создавать ViewModel для главной (стартовая) страницы.
1: $(function () { 2: 3: «use strict»; 4: 5: site.vm.viewModel = function () { 6: var 7: meta = site.utils.metaForDemo, 8: clock = new site.controls.Clock(), 9: dsPets = new site.controls.DataSource({ 10: items: site.utils.dataPets 11: }), 12: dsPeople = new site.controls.DataSource({ 13: items: site.utils.dataPeople, 14: events: { 15: selectedHandler: function (item) { 16: selectedItem(item); 17: } 18: } 19: }), 20: selectedItem = ko.observable(), 21: select = function (item) { 22: selectedItem(item); 23: }; 24: return { 25: meta: meta, 26: select: select, 27: selectedItem: selectedItem, 28: clock: clock, 29: dsPeople: dsPeople, 30: //pets: pets, 31: dsPets: dsPets 32: }; 33: }(); 34: 35: ko.applyBindings(site.vm.viewModel); 36: 37: });
Теперь немного HTML-разметки:
1: @{ 2: ViewBag.Title = «Контрол подброра»; 3: } 4: 5: <h2data-bind=»text: meta.title, 6: click: function () { window.location = meta.helplink(); }, 7: attr: { ‘style’: ‘cursor:pointer’ }»></h2> 8: <pdata-bind=»text: meta.description»></p> 9: 10: 11: <divclass=»row»> 12: <divclass=»span6″> 13: <h3>Список «Person»</h3> 14: <uldata-bind=»template: { ‘name’: ‘person-template.view’, foreach: dsPeople.items }»></ul> 15: </div> 16: <divclass=»span6″> 17: <h3>Список «Pets»</h3> 18: <uldata-bind=»template: { ‘name’: ‘pet-template.view’, foreach: dsPets.items }»></ul> 19: </div> 20: </div> 21: 22: <!— ko if: selectedItem —> 23: 24: <divclass=»row»> 25: <divclass=»span12″> 26: <h3>Выбранный пользователь</h3> 27: <divdata-bind=»template: { ‘name’: ‘person-template.view’, ‘data’: selectedItem }»></div> 28: </div> 29: <divclass=»span6″> 30: <h3>Первый способ</h3> 31: <divdata-bind=»template: { ‘name’: ‘person-template.edit’, data: selectedItem }»></div> 32: </div> 33: 34: <divclass=»span6″> 35: <h3>Второй способ</h3> 36: <divdata-bind=»template: { ‘name’: ‘person-template.edit2’, data: selectedItem }»></div> 37: </div> 38: </div> 39: 40: <!— /ko —> 41: 42: @section scripts { 43: <scriptsrc=»~/Scripts/app/dump.js»></script> 44: <script src=»/scripts/app/site.homeIndex.js»></script> 45: } 46: 47: @*<divdata-bind=»dump: dsPets.items»></div>*@ 48: <divclass=»clock»data-bind=»text: clock.time»></div>
Строки 5-7 выводят заголовок (header), на который можно кликнуть, чтобы перейти на наш блок. Это сделано лишь для примера связывания (binding), и не несет никакой смысловой нагрузки (Олег, надеюсь ты понял как можно использовать function в разметке knockout для связывания).
Строка 14: Выводим все записи из DataSource “Person” (dsPerson) при помощи шаблона (template), который берется из отдельного файла.
Примечание: все шаблоны загружаются из удаленных шаблонов при помощи специального модуля External Template Engine. Шаблоны я положил в папку Templates. Настройка (указание путей и всё такое) модуля происходит в файле site.core.js.
И что же мы видим?
После некоторых манипуляций с буквами английского алфавита, у меня появилось некоторое количество файлов с классами, сервисами и другой всякой фигней. Теперь можно запустить проект и посмотреть что получилось. Итак, у нас есть список пользователей:
Также на странице отображается список домашних питомцев:
Если мы выберем одного из пользователей, то он отобразится ниже:
А также станут доступны для редактирования данные этого пользователя. Для того чтобы вы смогли сравнить, я сделал это двумя способами. Первый способ “стандартный” при выборка происходит при помощи html-контрола <select>.
А вот второй способ “продвинутый” – уже использует DataSource, DBLookup и шаблоны для отображения.
Остановлюсь немного подробнее на контроле DbLookUp. Контрол имеет несколько шаблонов:
Нажимаем на кнопку вызова диалога.
Выбираем новое значение, нажимаем [выбрать] и, ву-а-ля! Новое значение “падает”
В качестве заключения
В качестве заключения хочу привести вашему вниманию некоторое количество ссылок:
Следующая статья будет о том самом контроле, который называется DataSource, и о том как можно просто из без особых усилий вывести данные с Web API на странице. На этом хочу закончить и сказать “спасибо за внимание”.
Подробнее: http://feedproxy.google.com/~r/blogmusor/~3/vxEA5DmR2WM/115
Источник: