ASP.NET MVC: Делаем голосование на сайте при помощи Knockout

В качестве вступления

Я буду строить решение на базе проекта, который был опубликован в предыдущей статье “ASP.NET MVC: И снова про форму обратной связи или куда еще втыкнуть Knockout”. Хочу чтобы статья получилась короткая, но максимально информативная.

Задача на эту статью – “реализовать голосование на сайте, с отображением результатов”.

ASP.NET MVC: Делаем голосование на сайте при помощи Knockout

Рис.1 “Опрос на сайте (пользователь еще не голосовал)”

И второй вариант отображения формы, это когда пользователь уже проголосовал.

106-knockout-poll-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

Читать комменты и комментировать

Добавить комментарий / отзыв



Защитный код
Обновить

ASP.NET MVC: Делаем голосование на сайте при помощи Knockout | | 2013-01-16 22:47:07 | | Программирование | | В качестве вступления Я буду строить решение на базе проекта, который был опубликован в предыдущей статье “ASP.NET MVC: И снова про форму обратной связи или куда еще втыкнуть Knockout”. Хочу чтобы | РэдЛайн, создание сайта, заказать сайт, разработка сайтов, реклама в Интернете, продвижение, маркетинговые исследования, дизайн студия, веб дизайн, раскрутка сайта, создать сайт компании, сделать сайт, создание сайтов, изготовление сайта, обслуживание сайтов, изготовление сайтов, заказать интернет сайт, создать сайт, изготовить сайт, разработка сайта, web студия, создание веб сайта, поддержка сайта, сайт на заказ, сопровождение сайта, дизайн сайта, сайт под ключ, заказ сайта, реклама сайта, хостинг, регистрация доменов, хабаровск, краснодар, москва, комсомольск |
 
Поделиться с друзьями: