ASP.NET MVC: MVVM на HTML или использование knockout при создании сайта (часть 2 из 2).
Сайтостроение | создано: 16.09.2012 | опубликовано: 16.09.2012 | обновлено: 13.01.2024 | просмотров: 13903 | всего комментариев: 6
В этой части закончим начатое в первой части, а именно пример сайта на с формой обратной связи с использованием Knockout.
Доведем форму до ума
В первой части статьи была подготовлена основа для формы обратной связи, в этой части закончим начатое. Я добавил некоторое количество полей на форму. Теперь разметка формы выглядит так:
<h3 data-bind="text: view.title"></h3> <p data-bind="text: sendResult"></p> <div data-bind="ifnot: isbusy, visible: sended"> <p> <label for="Subject">Выберите тему сообщения</label> <select data-bind="options: subjects, value: vm().Subject, optionsCaption:'выбрать тему'" id="Subject"></select> <small>загружено тем: <span data-bind="text: subjects().length"></span>шт.</small> <br /> <span data-bind="visible: vm().Subject">Выбранная тема: <b> <span data-bind="text: vm().Subject"></span></b> </span> </p> <p> <label for="userName">Ваше имя</label> <input type="text" data-bind="value: vm().UserName" id="userName" required /> </p> <p> <label for="email">Ваш почтовый адрес для ответа</label> <input type="email" data-bind="value: vm().Email" id="email" required /> </p> <p> <label for="message">Тескт сообщения</label> <textarea id="message" data-bind="value: vm().Message" rows="5" required></textarea> </p> <p> <button data-bind="click: sendMessage">Отправить сообщение</button> </p> </div> @section scripts { @Scripts.Render("~/bundles/koval") <script src="@Scripts.Url("~/js/site.core.js")"></script> <script src="@Scripts.Url("~/js/site.service.feedback.js")"></script> <script src="@Scripts.Url("~/js/site.vm.feedback.js")"></script> }
Поясню некоторые строки этого листинга:
- строка 2: сначала выводит приглашение заполнить все поля, при удачной попытке отправки отображает благодарность, при неудачной, соответственно, сообщение о неработоспособности сервера или вежливое напоминание, что поля надо заполнять правильно;
- строка 6: была доработана, добавлена дополнительная опция “выбрать тему”;
- строка 7-11: выбранная тема сообщения показывается именно тут.
Новый JsonResult
Напишем новый метод контролера Ajax, который как раз и должен будет отправлять сообщение администратору.
/// <summary> /// Отправленная с формы модель /// будет приходить сюда /// </summary> /// <param name="model"></param> /// <returns></returns> [HttpPost] public JsonResult SendFeedback(FeedbackViewModel feedback) { string message = "Простите ошибка. Не могу отправить сообщение. Возможно форма неверно заполнена или проблемы на сервере."; bool sended = false; if (ModelState.IsValid) { // реальная отправка сообщения message = "Спасибо за ваше сообщение. Приходите еще!"; sended = true; } return Json(new { Message = message, Sended = sended }); }
Опять вернемся Javascript
А теперь на код изменившегося ViewModel’а для javascript:
/////////////////////////////////////////////////////////////// // site.feedback // Работает через dataService с объектами на форме // Feedback // автор: calabonga.net /////////////////////////////////////////////////////////////// (function (site) { "use strict"; site.vm.feedbackViewModel = function () { var view = { title: "Отправка сообщения" }, subjects = ko.observableArray([]), sendResult = ko.observable("Заполните все поля формы, пожалуйста"), isbusy = ko.observable(false), cansended = ko.observable(true), feedback = ko.observable({ "Subject": ko.observable(), "UserName": ko.observable(), "Email": ko.observable(), "Message": ko.observable() }), loadSubjects = function () { isbusy(true); site.services.feedbackForm.loadSubjects(callbackSubjects); }, callbackSubjects = function (json) { isbusy(false); ko.mapping.fromJS(json, {}, subjects); var total = subjects().length; }, sendMessage = function () { sendResult("Ждите. Идет отправка сообщения"); isbusy(true); site.services.feedbackForm.sendFeedback(JSON.stringify(feedback), callbackMessage); }, callbackMessage = function (json) { isbusy(false); cansended(json.Sended ? false : true) sendResult(json.Message); }; loadSubjects(); return { view: view, vm: feedback, isbusy: isbusy, sendResult: sendResult, sended: cansended, subjects: subjects, sendMessage: sendMessage } }(); })(site);
Как не трудно заметить, добавились новые свойства и новый ViewModel для модели FeedbackViewModel:
/////////////////////////////////////////////////////////////// // ViewModel для отправки feedback на сервер // автор: calabonga.net /////////////////////////////////////////////////////////////// function FeedbackViewModel(subject, userName, email, message) { this.Subject = subject; this.UserName = userName; this.EmailAdrress = email; this.Message = message; };
Вот так теперь выглядит форма обратной связи:
А теперь опишу как это работает. Сейчас валидация объекта не предусмотрена. Как можно догадаться, проверку на правильность ввода пользователя проверяет метод контролера SendFeedback. У меня в планах показать, как можно использовать валидацию отправляемого объекта при помощи Knockout.Validation. И это я сделаю чуть позже, а пока посмотрите как работает текущий вариант формы.
Так выглядит форма если пользователь ввел неправильные данные. Подчеркнутое сообщение приходит как результат действия метода контроллера (то есть это серверная валидация):
Вот так форма отображается, если пользователь отправил верные данные:
Работает всё прекрасно, вот только пользователь, ни коим образом не знает о том, какую именно ошибку он совершил, а если бы форма была посложнее? Очень трудно было бы определить, в каком именно поле была допущена ошибка. Решить данную проблему поможет Knockout.Validation. Раз у ж мы используем ko, то и валидацию будем использовать на его основе, хотя нельзя забывать что существует еще и jquery.validation (и другие, сторонние разработки). Более того, существует вариант использовать jquery.validation в knockout.
Knockout.Validation в действии
Так как сборки (пакеты) уже все подключены. Мне остается немного подправить Javascript ViewModel’а чтобы заработала валидация. Вот измененные строки, которые немного дополнили объявление feedback:
feedback = ko.validatedObservable({ "Subject": ko.observable().extend({ required: true }), "UserName": ko.observable().extend({ required: true, minLength: 4 }), "Email": ko.observable().extend({ required: true, email: true }), "Message": ko.observable().extend({ required: true, minLength: 10 }) }),
Обратите внимание, что сам объект feedback стал теперь не просто ko.observable(), а ko.validatedObservable(). И еще надо немного на форме подправить привязку формы отправки:
<p> <button data-bind="click : sendMessage, enable: vm().isValid()">Отправить сообщение</button> </p>
Теперь кнопка отправки будет влючена, только если объект feedback будет валиден (правильно заполнен). Правда же ничего сложного? Если попробовать ввести некорректные данные, форм заартачится и вывалит кучу сообщений:
Дополнительная информация по типам валидации расширяемости свойств можно посмтреть на сайте плагина. Кстати, кажется не очень удачная идея отображать русскому пользователю сообщения на английском языке. Можно скачать локализацию положить ее в папку scripts под названием knockout.validation.ru-RU.js. Более ничего делать не надо, даже добавлять в пакет (Bundle), потому файл будет подключен автоматически из-за того, что виртуальный путь до пакета Knockout.Validation использует “*”.
bundles.Add(new ScriptBundle("~/bundles/koval").Include( "~/Scripts/knockout.validation.*"
Обновив страницу, можно будет читать сообщения на русском языке.
Ну, и на последок, остается немного разукрасить выводимое сообщение, что они были более заметны. Нужно в CSS задать стиль validationMessage.
.validationMessage { background-color:red; color:white; padding:5px; }
Вот окончательный вариант формы обратной связи:
Вместо заключения
Вот наверное и всё. Пишите комментарии.
Комментарии к статье (6)
Спасибо!
Отличное intro!
большое спасибо за ввидение в кнокаут!
Спасибо, хорошая статья!
Вот вопрос а как привязать к
List<string> subjects = new List<string>() { "Заявка на регистрацию блога на calabonga.net", "Связь с администратором", "Связь с блогером", "Вопрос об копирайтах", "Благодарственное письмо", "Желание поблагодарить материально" };
этому выражению почту для каждой например для блогера blog@mail.ru