使用Ajax表单的Modelstate

时间:2009-03-23 04:00:57

标签: asp.net-mvc ajax model state modelstate

我正在使用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

问题是当发生模型状态错误时,不会返回modelstate viewdata。我怀疑这可能是因为我没有指定更新目标ID。但我不能设置另一个updatetargetid因为我已经有了。有什么想法吗?

2 个答案:

答案 0 :(得分:5)

 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部分编辑视图

“%&gt;

<%= 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; }
    }

使用此代码,它可以按照您的意愿工作。 请注意,我的“发布”编辑操作中没有将任何模型传递给部分视图。 获取渲染的视图会从发布请求中获取所需的所有值。

答案 1 :(得分:0)

好吧,我已经弄明白了。谢谢你的回复。为了将来的参考,我要做的是设置一个主分区,我的所有内容都会进入。然后,我总是将updateTargetID设置为该分隔符,这样它显示的内容无关紧要,只是显示它。这实际上变得更容易,因为您不必浪费Javascript函数来设置其他div标签的开启和关闭,因为您只使用了一个不断更新的标签。