ASP.NET MVC: Делаем голосование на сайте при помощи Knockout
Рис.1 “Опрос на сайте (пользователь еще не голосовал)”
И второй вариант отображения формы, это когда пользователь уже проголосовал.
Рис.2 “Опрос на сайте (пользователь уже голосовал)”
Звучит и выглядит просто, и поэтому я стороной обойду загрузку данных с сервера, запись данных на сервер, чтение настроек и проверку cookies, чтобы по возможности максимально рассказать о Knockout. Итак, если учесть, что все приготовления выполнены, то можно сразу приступить к программированию.
Входные данные
В папке Scripts/App создаю новый файл site.vm.polls.js. Теперь первым делом определю формат данных для объекта (Poll) (листинг 1):
1: var pollData = {
2: "question": "За двумя зайцами погонишься...",
3: "answers": [
4: { votes: 11, name: "ни одного не поймаешь." },
5: { votes: 5, name: "больше двух не поймаешь." },
6: { votes: 15, name: "ни одного волка не поймаешь." },
7: { votes: 9, name: "порвешься на две части." },
8: { votes: 39, name: "зачем бегать, лучше на авто!" }
9: ],
10: "selectedAnswer": null};
Это, так сказать, входные данные. В моем случае, они “жестко” прописаны в коде. Вы же можете сделать получение данных для опроса с сервера, через Web API, или с сервиса WCF. Немного комментариев относительно представленного кода.
- Строка 2: Сам вопрос.
- Строка 3-8: Это предложенные варианты ответа на поставленный вопрос.
- Строка 10: Ответ, который возможно уже дал пользователь, посещая сайт. Вы можете хранить его в базе данных или даже в cookies. Сейчас он у меня null, поэтому форма должна отобразить список ответов и вопрос. А если поле было заполнено (выбранный ответ), то форма должна отобразить результаты голосования.
Класс Answer (Ответ)
В предыдущем листинге (листинг 1) в строка 3 эти самые ответы на вопрос. “Завернем” класс в JavaScript (листинг 2):
1: site.vm.Answer = function (value, total) {
2: var isSelected = ko.observable(false),
3: votes = ko.observable(total),
4: name = ko.observable(value);
5: return {
6: isSelected: isSelected,
7: name: name,
8: votes: votes
9: };
10: },
Всё просто, единственное, что хотелось быть отметить, что свойство isSelected будет указыват на то выбран ли ответ в списке вариантов или нет.
Класс Poll (Опрос)
Этот класс и будет представляет “входные данные” (см. листинг 1). Самый большой класс в моем решении (листинг 3).
1: site.vm.Poll = function (data) {
2: var selectedItem = ko.observable(new site.vm.Answer()),
3: question = ko.observable(data.question),
4: answers = ko.observableArray([]),
5: answer = ko.observable(),
6: maxVotes = ko.observable(),
7: init = function () {
8: var max = 0;
9: var i;
10: for (i in data.answers) {
11: var cur = data.answers[i].votes;
12: if (cur && cur>max) {
13: max = cur;
14: }
15: }
16: max = Math.round(max * 1.1);
17: maxVotes(max);
18: for (i in data.answers) {
19: answers.push(new site.vm.Answer(data.answers[i].name, data.answers[i].votes));
20: }
21: if (data.selectedAnswer) {
22: answer(data.selectedAnswer);
23: }
24: },
25: setSelected = function (item) {
26: if (!item.isSelected()) {
27: selectedItem(item.name());
28: ko.utils.arrayForEach(answers(), function (i) {
29: if (i.isSelected && i.isSelected()) { i.isSelected(false); }
30: });
31: item.isSelected(true);
32: }
33: };
34:
35: init();
36:
37: return {
38: max: maxVotes,
39: selectedItem: selectedItem,
40: question: question,
41: answers: answers,
42: answer: answer,
43: setSelected: setSelected
44: };
45: };
И опять немного комментариев:
- Строка 2: Представляет выбранный пользователем ответ.
- Строка 6: Вообще-то, это свойство (maxVotes) я ввел только для того, чтобы правильно работал jQuery UI Progressbar, при помощи которого я планирую отображать результаты.
- Строка 7: Инициализация класса на основании входных данных. Запуск инициализации происходит в строке 35.
ViewModel для формы
На форме может быть много опросов, в моем варианте он один. Создаем ViewModel для формы Index.cshtml. Вот так выглядит pollViewModel (листинг 4):
1: site.vm.pollViewModel = function () {
2: var message = ko.observable("Выберите ваш вариант ответа на вопрос."),
3: poll = site.vm.Poll(pollData),
4: save = function () {
5: poll.answer(poll.selectedItem());
6: };
7:
8: return {
9: save: save,
10: poll: poll,
11: message: message
12: };
13: }();
Строка 2: Сообщение для пользователя. Мне не пригодилось, но можно использовать для вывода ошибок при работе сервиса.
Строка 3: Создаем экземпляр класса голосования (см. листинг 3).
Строка 4: Функция сохранения результатов голосования. В моем решении это просто обновления свойства answer. Но вы можете отправить результат на сервер или сохранить в cookies.
Магия Knockout – applyBindings
Голосование (Poll) я планирую показать на главной странице (то есть в котроллере Home, метод – Index). Я открыл представление (index.cshtml) и полностью его отчистил, и добавил туда такую разметку:
1: <divdata-bind="ifnot: poll.answer">
2: <h2data-bind="text: poll.question">h2>
3: <h4data-bind="text: message">h4>
4: <divdata-bind="foreach: poll.answers">
5: <divdata-bind="click: $parent.poll.setSelected"class="big">
6: <inputtype="radio"value="true" data-bind="checked: isSelected().toString()"class="poll"/>
7: <spandata-bind="text: name, css: {'selected': isSelected}">span>
8: div>
9: div>
10: <p>
11: <buttondata-bind="click: save">голосоватьbutton>
12: p>
13: div>
14: <divdata-bind="if: poll.answer">
15: <h2data-bind="text: poll.question() ' ' poll.answer()">h2>
16: <divdata-bind="foreach: poll.answers">
17: <spandata-bind="text: name">span>
18: <divdata-bind="progressbar: {value: votes(), max: $parent.poll.max()}">div>
19: <br/>
20: div>
21: div>
Всё на форме просто и, надеюсь, понятно. Единственное, что хотелось бы отметить, для отображения результатов в шаблоне (строка 18) используется bindingHandler, который я назвал “progressbar”. Когда вы установите nuget-пакет JsJite, у вас в папке scripts/app появится файл site.bindingHandlers.js, в котором уже много полезных “штучек”.
Заключение
В качестве заключения хочу предложить создать демо-проект и поэкспериментировать.
Подробнее: http://feedproxy.google.com/~r/blogmusor/~3/ReoYRvxCyJU/106
Дайджест новых статей по интернет-маркетингу на ваш email
Новые статьи и публикации
- 2024-09-30 » Как быстро запустить Laravel на Windows
- 2024-09-25 » Next.js
- 2024-09-05 » OpenAI рассказал, как запретить ChatGPT использовать содержимое сайта для обучения
- 2024-08-28 » Чек-лист: как увеличить конверсию интернет-магазина на примере спортпита
- 2024-08-01 » WebSocket
- 2024-07-26 » Интеграция с Яндекс Еда
- 2024-07-26 » Интеграция с Эквайринг
- 2024-07-26 » Интеграция с СДЕК
- 2024-07-26 » Интеграция с Битрикс-24
- 2024-07-26 » Интеграция с Travelline
- 2024-07-26 » Интеграция с Iiko
- 2024-07-26 » Интеграция с Delivery Club
- 2024-07-26 » Интеграция с CRM
- 2024-07-26 » Интеграция с 1C-Бухгалтерия
- 2024-07-24 » Что такое сторителлинг: техники и примеры
- 2024-07-17 » Ошибка 404: что это такое и как ее использовать для бизнеса
- 2024-07-03 » Размещайте прайс-листы на FarPost.ru и продавайте товары быстро и выгодно
- 2024-07-01 » Профилирование кода в PHP
- 2024-06-28 » Изучаем ABC/XYZ-анализ: что это такое и какие решения с помощью него принимают
- 2024-06-17 » Зачем вам знать потребности клиента
- 2024-06-11 » Что нового в работе Яндекс Метрики: полный обзор обновления
- 2024-06-11 » Поведенческие факторы ранжирования в Яндексе
- 2024-06-11 » Скорость загрузки сайта: почему это важно и как влияет на ранжирование
- 2024-05-27 » Подборка сервисов для расшифровки аудио в текст
- 2024-05-27 » PostgreSQL 16. Изоляция транзакций. Часть 2
- 2024-05-06 » Как настраивать конверсионные стратегии: работа над ошибками
- 2024-04-22 » Комментирование кода и генерация документации в PHP
- 2024-04-22 » SEO в России и на Западе: в чем основные отличия
- 2024-04-22 » SEO для международного масштабирования
- 2024-04-22 » Как использовать XML-карты для продвижения сайта
Полезнее знать несколько мудрых правил, которые всегда могли бы служить тебе, чем выучиться многим вещам, для тебя бесполезным Сенека Луций Анней - (1 до н. э. / 1 н. э.- 65 н. э.) - римский государственный деятель, писатель, философ |