MVC 根据所选选项动态更改创建表单并将其保存在数据库中

本文关键字:表单 保存 数据库 存在 创建 选项 动态 MVC | 更新日期: 2023-09-27 17:57:03

>我有 4 Models帖子、汽车、类别、子类别。汽车有一些额外的属性,并且还继承了帖子,帖子Model包括类别ID和子类别ID的属性的所有内容。我需要创建一个可以动态更改的View,以便能够保存汽车。用户首先看到类别和子类别的两个dropdown列表,选择这两个列表后,它会加载正确的PartialView。一切都很好,但是由于一些原因,我无法将其保存在数据库中。

首先,我不知道在哪里声明页面的model,它应该在创建View中 - 这意味着它不能更改,因为我只希望输入字段出现和动态更改,但页面不应该重新加载。这也意味着由于Car Model有一些额外的属性,包括stringint,我无法创建一个具有所有可能属性的ViewModel string因为不nullable。如果在PartialView中声明了model,这意味着我可以为汽车和邮政创建单独的ViewModel,但表单标签将在PartialView中,类别和子类别的dropdown列表位于创建View中的此表单标签之外,因为它不应该更改。当表单发布时,我收到一个错误,就像我使用Request.Form["..ID"];来获取类别ID和子类别ID一样。我需要以某种方式解决这个问题。

我尝试使用 Ajax ,但这出现错误,指出类别 ID 和子类别 ID 的空条目,仅在表单标签中传递值。

Models

public class Category
{
    public int CategoryID { get; set; }
    public string Name { get; set; }        
}
public class SubCategory
{        
    public int SubCategoryID { get; set; }
    [Required]
    public string Name { get; set; }
    [ForeignKey("CategoryID")]
    public virtual Category Category { get; set; }
    public int? CategoryID { get; set; }        
}
public class Post
{
    public int PostID { get; set; }
    public string Title { get; set; }
    public string Msg { get; set; }
    [DataType(DataType.Currency)]
    public decimal Price { get; set; }
    public string PostCode { get; set; }
    [DataType(DataType.ImageUrl)]
    public string MainPhotoPath { get; set; }
    public DateTime PostedAt { get; set; }
    public bool Active { get; set; }        
    public string ApplicationUserId { get; set; }
    [ForeignKey("SubCategoryID")]
    public virtual SubCategory SubCategory { get; set; }
    public int SubCategoryID { get; set; }        
    public int CategoryID { get; set; }
    public string CityName { get; set; }
}
public class Car : Post
{
    public string Make { get; set; }
    public int Year { get; set; }
    public int EngineSize { get; set; }
    public int Mileage { get; set; }
    public string FuelType { get; set; }
    public string Transmission { get; set; }
}

创建View

@using Mvc.CascadeDropDown
@{
    ViewBag.Title = "Create";
}
<div class="row">
<div class="col-lg-12">
    <div class="text-center">
        <h2>Add a new Post</h2>
        <h3 id="CityDiv">City: @ViewBag.Location</h3>
    </div>
    <div class="col-lg-12">
        @Html.Action("Menu")
        <div id="createNewPost">
        </div>
    </div>        
</div>
</div>
<script type="text/javascript">
$("#SubCategoryID").click(function () {
    var selectedSubCategory = $("#SubCategoryID").val();
    if (selectedSubCategory == 4) {
        var url = "/Posts/CarPartial/";
        $.ajax({
            url: url,
            cache: false,
            type: "POST",
            success: function (data) {
                $("#createNewPost").html(data);
            },
            error: function (reponse) {
                alert("error : " + reponse);
            }
        });
    }        
    else {
        var url = "/Posts/PostPartial/";
        $.ajax({
            url: url,
            cache: false,
            type: "POST",
            success: function (data) {
                $("#createNewPost").html(data);
            },
            error: function (reponse) {
                alert("error : " + reponse);
            }
        });
    }
});
$("#CreatePostFormID").submit(function () {
    var _categoryId = $("#CategoryID").val();
    var _subcategoryId = $("#SubCategoryID").val();
    var url = "/Posts/Create/";
    $.ajax({
        url: url,
        data: { cId: _categoryId, subId: _subcategoryId },
        cache: false,
        type: "POST",
        success: function (data) {
            alert("ok");
        },
        error: function (reponse) {
            alert("error : " + reponse);
        }
    });
});
</script>
@section Scripts {
@Scripts.Render("~/bundles/jqueryval")
}

用于选择类别和子类别的菜单

@model PostIt.Models.DropDown
<h4>
Please choose a category first
</h4>
@using (Html.BeginForm())
{
    @Html.DropDownListFor(m => m.CategoryModel, new SelectList(Model.CategoryModel, "CategoryID", "Name"), new { @id = "CategoryID", @class = "form-control col-md-offset-2 margin-bottom" })
<select id="SubCategoryID" name="SubCategoryID" class="form-control col-md-offset-2 margin-bottom"></select>
}
<script language="javascript" type="text/javascript">
$(window).load(function () {
    $("#CategoryID").click(function () {
        var _categoryId = $("#CategoryID").val();
        var procemessage = "<option value='0'> Please wait...</option>";
        $("#SubCategoryID").html(procemessage).show();
        var url = "/Posts/GetSubCategoryById/";
        $.ajax({
            url: url,
            data: { categoryid: _categoryId },
            cache: false,
            type: "POST",
            success: function (data) {
                var markup = "<option value='0'>Select a subcategory</option>";
                for (var x = 0; x < data.length; x++) {
                    markup += "<option class='selectedSubCategory' value=" + data[x].Value + ">" + data[x].Text + "</option>";
                }
                $("#CategoryID").val(_categoryId);
                $("#SubCategoryID").html(markup).show();
            },
            error: function (reponse) {
                alert("error : " + reponse);
            }
        });
    });
});
</script>

如果子类别只需要 Post Model,则PartialView加载到createNewPost div

@model PostIt.Models.PostViewModel
@using (Html.BeginForm("Create", "Posts", FormMethod.Post, new { enctype = "multipart/form-data", id = "CreatePostFormID" }))
        {
@Html.AntiForgeryToken()
<div class="form-horizontal">
        <div class="form-group">
            @Html.LabelFor(model => model.Title, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.Title, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.Title, "", new { @class = "text-danger" })
            </div>
        </div>
        <div class="form-group">
            @Html.LabelFor(model => model.Msg, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.Msg, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.Msg, "", new { @class = "text-danger" })
            </div>
        </div>
        <div class="form-group">
            @Html.LabelFor(model => model.Price, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.Price, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.Price, "", new { @class = "text-danger" })
            </div>
        </div>
        <div class="form-group">
            @Html.LabelFor(model => model.PostCode, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.PostCode, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.PostCode, "", new { @class = "text-danger" })
            </div>
        </div>
        <div class="form-group">
            @Html.LabelFor(model => model.MainPhotoPath, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.TextBoxFor(model => model.MainPhotoPath, new { type = "file" })
                @Html.ValidationMessageFor(model => model.MainPhotoPath, "", new { @class = "text-danger" })
            </div>
        </div>
        <div class="form-group">
            <div class="col-md-offset-2 col-md-10">
                <input type="submit" value="Create" class="btn btn-default" id="SubmitID" /> | @Html.ActionLink("Cancel", "Index")
            </div>
        </div>
</div>
}

ActionMethod创建帖子。

public ActionResult Create([Bind(Include = "Title,Msg,Price,PostCode,MainPhotoPath")] PostViewModel post, HttpPostedFileBase image, int cId, int subId)
    {
        Post newPost = new Post();
        //var cId = Request.Form["CategoryModel"];
        //var subId = Request.Form["SubCategoryID"];
        newPost.CategoryID = Convert.ToInt32(cId);
        newPost.SubCategoryID = Convert.ToInt32(subId);
        newPost.Title = post.Title;
        newPost.Msg = post.Msg;
        newPost.Price = post.Price;
        newPost.PostCode = post.PostCode;
        newPost.PostedAt = DateTime.Now;
        newPost.Active = false;
        newPost.ApplicationUserId = User.Identity.GetUserId();
        newPost.CityName = Server.HtmlEncode(Request.Cookies["location"].Value);
        Debug.WriteLine(Request.Files.Count);
        HttpPostedFileBase file = Request.Files[0];
        string fileName = file.FileName;
        int fileSize = file.ContentLength;
        if (fileSize >= 10)
        {
            string path = Server.MapPath("~/Upload_Files/images/");
            newPost.MainPhotoPath = "~/Upload_Files/images/" + fileName;
            if (!Directory.Exists(path))
            {
                Debug.WriteLine("Creating new directory");
                Directory.CreateDirectory(path);
            }
            file.SaveAs(Server.MapPath("~/Upload_Files/images/" + fileName));
        }
        else
        {
            newPost.MainPhotoPath = "~/Images/no_image.png";
        }

        if (ModelState.IsValid)
        {
            db.Posts.Add(newPost);
            db.SaveChanges();
            return RedirectToAction("Index", "Home");
        }
        return View("Create", post);
    }

MVC 根据所选选项动态更改创建表单并将其保存在数据库中

我并不是要转储太多代码,我已经吸取了教训。

如果有人在为同样的问题而苦苦挣扎,答案如下。

使用 @using (Html.BeginForm 标记在PartialView中声明model,以便您可以根据model创建表单。创建表单可以通过Ajax动态更改,因此基本上一个创建表单可以处理任何模型。

由于包含必要 CategoryID 和 SubCategory ID 值dropdown列表位于表单标记之外,因此它不会传递给控制器,即使在顶部使用 Ajax,也只会破坏它。首先,它将调用ActionResult但没有为 ID 传递任何值,返回错误,甚至不会调用 Ajax 函数。

为了解决它,在控制器中为正确的model创建PartialView时,我随它传递 ID 值。

Ajax致电获取邮政PartialView

var url = "/Posts/PostPartial/";
        $.ajax({
            url: url,
            data: { cid : selectedCategory, sid : selectedSubCategory },
            cache: false,
            type: "POST",
            success: function (data) {
                $("#createNewPost").html(data);
            },
            error: function (reponse) {
                alert("error : " + reponse);
            }
        });

ActionResult控制器内部以返回正确的PartialView。在这种情况下,它是一个帖子。

public ActionResult PostPartial(int cid, int sid)
    {
        PostViewModel viewmodel = new PostViewModel();
        viewmodel.CategoryID = cid;
        viewmodel.SubCategoryID = sid;
        return PartialView("CreatePost", viewmodel);
    }

上面的创建ActionResult工作正常,但是名为PostViewModel的ViewModel也必须具有CategoryID和SubCategoryID的属性,并且必须在控制器中bind属性才能创建ActionResult