MVC 根据所选选项动态更改创建表单并将其保存在数据库中
本文关键字:表单 保存 数据库 存在 创建 选项 动态 MVC | 更新日期: 2023-09-27 17:57:03
>我有 4 Models
帖子、汽车、类别、子类别。汽车有一些额外的属性,并且还继承了帖子,帖子Model
包括类别ID和子类别ID的属性的所有内容。我需要创建一个可以动态更改的View
,以便能够保存汽车。用户首先看到类别和子类别的两个dropdown
列表,选择这两个列表后,它会加载正确的PartialView
。一切都很好,但是由于一些原因,我无法将其保存在数据库中。
首先,我不知道在哪里声明页面的model
,它应该在创建View
中 - 这意味着它不能更改,因为我只希望输入字段出现和动态更改,但页面不应该重新加载。这也意味着由于Car Model
有一些额外的属性,包括string
和int
,我无法创建一个具有所有可能属性的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);
}
我并不是要转储太多代码,我已经吸取了教训。
如果有人在为同样的问题而苦苦挣扎,答案如下。
使用 @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
。