Здравствуйте, mogadanez, Вы писали:
M>* Post надо делать _только_ через Ajax.
M>* при этом показывать "крутяшку"
M>* назад прилетает :
M> ** либо структура с ошибками ( например те которые нельзя просто проверить на клиенте )
M> ** либо разрешение сделать редирект( напрмиер просто url )
Полностью согласен, делается это не сложно, а результат красивый. Только добавлю свои пять копеек.
* Оно должно корректно отрабатывать если нет ява скрипта (есть придурки, которые бегают с NoScript в Фаерфоксе)
* Оно должно работать с валидацией (клиентская и серверная)
Давайте рассмотрим простейший пример типа «форма логина на сайте».
Вьюшка:
<fieldset class="smallest">
<% using (Html.BeginForm("login", "account", FormMethod.Post, new{id="loginForm"})) { %>
<%= Html.HiddenFor(m => Model.ReturnUrl)%>
<ol>
<li>
<%= Html.LabelFor(model => Model.LoginOrEmail)%>
<%= Html.TextBoxFor(model => Model.LoginOrEmail, new { @class = "text bigest", id = "login", tabindex = "1" })%>
<%= Html.ValidationMessageFor(model => Model.LoginOrEmail)%>
</li>
<li>
<%= Html.LabelFor(model => Model.Password)%>
<%= Html.PasswordFor(model => Model.Password, new { @class = "text big", tabindex = "2" })%>
<%= Html.ValidationMessageFor(model => Model.Password)%>
</li>
<li class="checkbox">
<%= Html.CheckBoxFor(m => Model.Persist, new {tabindex = "3"})%>
<%= Html.LabelFor(m => Model.Persist)%>
</li>
<li>
<%= Html.Button("Войти") %>
</li>
</ol>
<% } %>
<script type="text/javascript">
$(document).ready(function () { tryAjaxFormSubmit('loginForm'); });
</script>
</fieldset>
Обычная такая вьюшка, но если у чувака есть JS, то вызовется функция
tryAjaxFormSubmit, которая выглядит так:
function tryAjaxFormSubmit(formId) {
var f = $("#" + formId);
f.submit(function () {
var validator= f.validate();
if (validator.valid()) {
var action = f.attr("action");
var serializedForm = f.serialize();
$.ajax({
type: 'POST',
url: action,
dataType: 'json',
data: serializedForm,
beforeSend: function () { setFormStateLoading('loginForm', true); },
success: function (result) {
if (result.RedirectUrl != null && result.RedirectUrl != '')
window.location = result.RedirectUrl;
else {
validator.showErrors(result.Errors);
setFormStateLoading('loginForm', false);
}
}
});
}
return false;
});
}
Эта функция перехватывает сабмит формы, валидирует ее с помощью jQuery.validation, если валидация на клиенте прошла, то форма сабмитится на сервер.
Метод контроллера:
[HttpPost, OutputCache(Duration = 60), HandleAjaxRequest]
public ActionResult Login(UserLoginInput input)
{
if (!ModelState.IsValid)
{
return View();
}
var user = _userService.GetByLoginOrEmail(input.LoginOrEmail);
FormsAuthentication.SetAuthCookie(user.Login, input.Persist);
if (!String.IsNullOrEmpty(input.ReturnUrl))
return Redirect(input.ReturnUrl);
return RedirectToAction("Index", "Pages");
}
Все как обычно, кроме атрибута
HandleAjaxRequest, который как раз и обрабатывает результат экшена контроллера.
HandleAjaxRequest:
public class HandleAjaxRequestAttribute : ActionFilterAttribute
{
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
if (!filterContext.HttpContext.Request.IsAjaxRequest()) return;
var state = filterContext.Controller.ViewData.ModelState;
if (!state.IsValid)
{
var response = new JsonResponse
{
Status = Status.Error,
Errors = state.ToJson()
};
filterContext.Result = new JsonResult() { Data = response };
return;
}
if ((filterContext.Result is RedirectToRouteResult || filterContext.Result is RedirectResult))
{
string url;
if (filterContext.Result is RedirectResult)
{
url = (filterContext.Result as RedirectResult).Url;
}
else
{
var result = (RedirectToRouteResult)filterContext.Result;
url = UrlHelper.GenerateUrl(result.RouteName, null, null, result.RouteValues, RouteTable.Routes, filterContext.RequestContext, false);
}
var response = new JsonResponse
{
Status = Status.Ok,
RedirectUrl = url
};
filterContext.Result = new JsonResult { Data = response };
}
}
}
Суть атрибута в том, чтобы проверить какой был запрос, через Аякс или нет. Если через аякс, то перезаписываем результат экшена на JSON. Если были ошибки, то конвертим их массив строк ключ-значение, который с удовольствием кушает jquery.validation.
Вот в принципе и все. У кого есть JS то все происходит красиво, у кого нет — тоже не плохо