ASP.NET MVC: MVVM на HTML или использование knockout при создании сайта (часть 2 из 2).
Сайтостроение | создано: 16.09.2012 | опубликовано: 16.09.2012 | обновлено: 13.01.2024 | просмотров: 14160 | всего комментариев: 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