Модельное состояние с формой Ajax
-
21-08-2019 - |
Вопрос
Я использую форму AJAX для обновления элемента в базе данных.По завершении он возвращает частичное представление, в котором заново перечисляет все элементы и отображает их все в таблице.Проблема возникает, когда мне приходится добавить ошибку состояния модели в действие моего контроллера.Я не хочу возвращать список элементов при возникновении ошибки состояния модели, поскольку хочу показать пользователю ошибку с помощью ValidationMessage.Я думаю, что я мог бы сделать что-то подобное в своем контроллере:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult UpdateNewsItem(int newsID, string newsTitle, string newsDescription, string newsBeginningDate, string newsEndingDate)
{
List<Models.News> lstNewsItem = new List<News>();
//we need to grab the member so we can capture the user id
//for the corresponding news property
MembershipUser member = Membership.GetUser(User.Identity.Name);
//the news instance to use in case the viewdata is invalid
Models.News newsError = new Models.News();
//create the datetime objects
DateTime dtBeginningDate = DateTime.MinValue;
DateTime dtEndingDate = DateTime.MaxValue;
//the message we want to send whenever the user enters an invalid date
string strInvalidDateError = "Invalid date. Please use a format like '12/25/2008'";
//clean user input
newsTitle = Models.clsGlobals.CleanString(newsTitle);
newsDescription = Models.clsGlobals.CleanParagraph(newsDescription);
//newsTitle
if (string.IsNullOrEmpty(newsTitle))
{
newsError.Title = string.Empty;
ModelState.AddModelError("newsTitle", "You must enter a news title.");
}
//description
if (string.IsNullOrEmpty(newsDescription))
{
newsError.Description = string.Empty;
ModelState.AddModelError("newsDescription", "You must enter a news description.");
}
//beginningDate
if (string.IsNullOrEmpty(newsBeginningDate))
{
ModelState.AddModelError("newsBeginningDate", "You must enter a beginning date.");
}
//endingDate
if (string.IsNullOrEmpty(newsEndingDate))
{
ModelState.AddModelError("newsEndingDate", "You must enter an ending date.");
}
//set the beginning date
try
{
dtBeginningDate = DateTime.Parse(newsBeginningDate);
newsError.BeginningDate = dtBeginningDate;
}
catch (FormatException)
{
ModelState.AddModelError("newsBeginningDate", strInvalidDateError);
}
//set the ending date
try
{
dtEndingDate = DateTime.Parse(newsEndingDate);
newsError.EndingDate = dtEndingDate;
}
catch (FormatException)
{
ModelState.AddModelError("newsEndingDate", strInvalidDateError);
}
//data is validated, so we can begin the update
if (ModelState.IsValid == true)
{
try
{
//use to perform actions on db
Models.NewsDataContext dcNews = new Models.NewsDataContext();
//fetch the items that match what the user requested to edit
lstNewsItem = this.GetNewsItem(newsID);
//set news properties
foreach (Models.News news in lstNewsItem)
{
news.UserId = (Guid)member.ProviderUserKey;
news.Title = newsTitle;
news.Description = newsDescription;
news.EntryDate = DateTime.Now;
news.BeginningDate = dtBeginningDate;
news.EndingDate = dtEndingDate;
}//next
//update the transaction
dcNews.SubmitChanges();
//update the news list
return PartialView("NewsList", this.GetNewsItems());
}
//just to make sure everything goes as planned,
// catch any unhandled exceptions
catch (Exception ex)
{
ModelState.AddModelError("_FORM", ex);
}//end catch
}//end if valid modelstate
//invalid modelstate, so repopulate the viewdata and
//send it back
//the list to hold the entries
List<Models.News> lstErrorNewsItems = new List<Models.News>();
//set the remaining error properties
newsError.UserId = (Guid)member.ProviderUserKey;
newsError.NewsID = newsID;
newsError.EntryDate = DateTime.Now;
//add the item--there will only be one
//but the view is expecting a list so we will
//treat it like one
lstErrorNewsItems.Add(newsError);
return PartialView("EditNews", lstErrorNewsItems);
}//end actionresult
Проблема в том, что при возникновении ошибки состояния модели данные представления состояния модели не возвращаются.Я подозреваю, что это возможно потому, что я не указываю идентификатор цели обновления.Но я не могу установить другой updatetargetid, потому что он у меня уже есть.Есть идеи?
Решение 2
Хорошо, я понял это.Спасибо за ответ.На будущее мне нужно было настроить один главный разделитель, в который будет помещаться весь мой контент.Затем я всегда устанавливаю updateTargetID для этого разделителя, чтобы не имело значения, какой контент он отображает, а просто то, что он отображает его.На самом деле это оказывается проще, потому что вам не нужно тратить функции Javascript на включение и выключение других тегов div, потому что вы используете только тот, который постоянно обновляется.
Другие советы
if (!Model.IsValid) {
return PartialView("YourEditForm");
}
else
{
return View("YourIndexView");
}
Должно работать нормально для повторного отображения формы редактирования с ошибками проверки и всем остальным.ViewData заполняется из данных Post.
Большое обновление
Я провел несколько тестов, чтобы выяснить это.И придумал рабочий тестовый проект.вот несколько списков:
Мой контроллер тестирования
public class TestController : Controller
{
//
// GET: /Test/
List<TestData> data;
public TestController()
{
data = new List<TestData>();
for (var i = 0; i < 10; i++)
{
data.Add(new TestData(){Name=string.Format("TestData{0}",i.ToString().PadLeft(4,'0'))});
}
}
public ActionResult Index()
{
return View( data);
}
public ActionResult Edit(string name)
{
if (Request.IsAjaxRequest())
{
return PartialView("AjaxEdit", new TestData() { Name = name });
}
return View(new TestData() { Name = name });
}
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Edit(TestData testData)
{
ModelState.AddModelError("name", "incorrect name");
if (!ModelState.IsValid)
{
if (Request.IsAjaxRequest())
{
return PartialView("AjaxEdit");
}
}
return View();
}
}
Мой вид редактирования:
<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<AjaxValidationPartial.Models.TestData>" %>
<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
Edit
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<h2>Edit</h2>
<div id="editForm">
<% Html.RenderPartial("AjaxEdit",Model );%>
</div>
</asp:Content>
Мой вид частичного редактирования Ajax
" %><%= Html.ValidationSummary("Edit was unsuccessful. Please correct the errors and try again.") %>
<% using (Ajax.BeginForm(new AjaxOptions { UpdateTargetId = "editForm" }))
{%>
<fieldset>
<legend>Fields</legend>
<p>
<label for="Name">Name:</label>
<%= Html.TextBox("Name")%>
<%= Html.ValidationMessage("Name", "*")%>
</p>
<p>
<input type="submit" value="Save" />
</p>
</fieldset>
<% } %>
<div>
<%=Html.ActionLink("Back to List", "Index") %>
</div>
И мой класс модели TestData
public class TestData
{
public string Name { get; set; }
}
с этим кодом он работает так, как вы хотели.Обратите внимание, что я не передаю какую-либо модель для частичного просмотра в своем действии редактирования «Опубликовать».Представление, которое визуализируется, получает все необходимые значения из почтового запроса.