具有viewmodel属性的Mvc表单包含list <object>

时间:2016-10-12 14:15:58

标签: c# asp.net-mvc validation razor

我是MVC5的新手。我想在数据库中添加建筑细节。建筑物详细信息包括名称,房间详细信息列表等。用户可以添加建筑物详细信息,例如名称和房间详细信息列表。添加所有详细信息后,房间和建筑物详细信息列表将保存到数据库中。

Add Building Details Image

我有一个带有视图模型的表单,如下所示

BuildingViewModel.cs

public class Building
{
    public Building()
    {
        Rooms = new List<Room>();
        NewRoom = new Room();
    }

    [Required]
    public string Name { get; set; }

    public List<Room> Rooms { get; set; }

    public Room NewRoom { get; set; }

    public string Button { get; set; }
}

public class Room
{
    [Required]
    public string RoomName { get; set; }

    public string Area { get; set; }
}

这是我的视图Create.cshtml

@model Building
@{
    ViewBag.Title = "Create";
}

@using (Html.BeginForm())
{
    <h2>Create</h2>

    <h3>Building</h3>
    @Html.LabelFor(t => t.Name)
    @Html.TextBoxFor(t => t.Name)
    @Html.ValidationMessageFor(t => t.Name)  

    <br />
    <br />

    <fieldset>
        <legend>Room</legend>

        <div class="editor-label">
            @Html.LabelFor(model => model.NewRoom.RoomName)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.NewRoom.RoomName)
            @Html.ValidationMessageFor(model => model.NewRoom.RoomName)
        </div>

        <div class="editor-label">
            @Html.LabelFor(model => model.NewRoom.Area)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.NewRoom.Area)
            @Html.ValidationMessageFor(model => model.NewRoom.Area)
        </div>

        <p>
            <input type="submit" name="button" value="Add Room" />
        </p>
    </fieldset>

    <br />
    <table border="1" cellpadding="5px" cellspacing="0">
        <thead>
            <tr>
                <th>#</th>
                <th>Name</th>
                <th>Description</th>
            </tr>
        </thead>
        <tbody>
            @for (int i = 0; i < Model.Rooms.Count(); i++)
            {
                var room = Model.Rooms[i];
                <tr>
                    <td>@(i + 1)</td>
                    <td>@room.RoomName @Html.HiddenFor(t => room.RoomName)</td>
                    <td>@room.Area @Html.HiddenFor(t => room.Area)</td>
                </tr>
            }
        </tbody>
    </table>
    <br />

    <input type="submit" name="button" value="Create" />
}
<script src="~/Scripts/jquery-1.8.0.min.js"></script>
<script src="~/Scripts/jquery.validate.min.js"></script>
<script src="~/Scripts/jquery.validate.unobtrusive.min.js"></script>

这是我的控制器BuildingController.cs

public class BuildingController : Controller
{
    [HttpGet]
    public ActionResult Create()
    {
        var building = new Building();
        return View(building);
    }

    [HttpPost]
    public ActionResult Create(Building building)
    {
        switch (building.Button)
        {
            case "Add Room":
                if (ModelState.IsValid)
                {
                    building.Rooms.Add(building.NewRoom);
                    building.NewRoom = new Room();

                    return View(building);
                }
                break;

            case "Create":
                if (ModelState.IsValid)
                {
                    // TODO: save to db

                    return View();
                }
                break;
        }

        return View(building);
    }
}

我的问题是,当单击“添加房间”按钮时,它会在建筑物的“名称”属性中抛出验证错误。我想要的是,单击“添加房间”按钮时仅显示房间类属性的验证,并在单击“创建”按钮时显示建筑属性的验证错误。

Add Building Validation Error Image

我花了超过2周的时间来解决这个问题。请帮帮我......

感谢您宝贵的时间。

3 个答案:

答案 0 :(得分:1)

由于您的Building.Name属性为[Required],因此会引发验证错误。

因此,您只需删除[Require]属性和@Html.ValidationMessageFor(t => t.Name)即可。

答案 1 :(得分:0)

你在控制器方法中做得很多。我会将您的页面拆分为2个具有自己视图模型的局部视图。因为它们是具有不同数据要求的2个不同功能。

每个部分视图应包含每个操作的单独表单。然后将每个表单的提交按钮映射到控制器上的单独操作。

答案 2 :(得分:0)

最后,我找到了使用局部视图和Ajax URL帖子的解决方案。

以下是解决方案: - )

BuildingController.cs

public class BuildingController : Controller
{
    [HttpGet]
    public ActionResult Create()
    {
        var building = new Building();
        return View(building);
    }

    [HttpPost]
    public ActionResult Create(Building building)
    {
        switch (building.Button)
        {
            case "Add Room":
                if (ModelState.IsValid)
                {
                    building.Rooms.Add(building.NewRoom);
                    building.NewRoom = new Room();
                    ModelState.Clear();
                    return PartialView("_Room", building);
                }
                break;

            case "Create":
                if (ModelState.IsValid)
                {
                    // TODO: save to db

                    return Json("Building created successfully.", JsonRequestBehavior.AllowGet);
                }
                break;
        }

        return View(building);
    }
}

BuildingViewModel.cs

public class Building
{
    public Building()
    {
        Rooms = new List<Room>();
        NewRoom = new Room();
    }

    public string Button { get; set; }

    //[Required(AllowEmptyStrings = false, ErrorMessage = "The building name is required.")]
    public string Name { get; set; }

    public Room NewRoom { get; set; }
    public List<Room> Rooms { get; set; }
}

public class Room
{
    //[Required(AllowEmptyStrings = false, ErrorMessage = "The room name is required.")]
    public string RoomName { get; set; }

    public string Area { get; set; }
}

Create.cshtml

@model Building
@{
    ViewBag.Title = "Create";
 }

 @using (Html.BeginForm("Create", "Building", FormMethod.Post, new { @id = "commentForm" }))
{
<h2>Create</h2>

<h3>Building</h3>
@Html.LabelFor(t => t.Name)
@Html.TextBoxFor(t => t.Name, htmlAttributes: new { @class = "create" })
@Html.ValidationMessageFor(t => t.Name)  

<br />
<br />

<div id="rooms">
    @Html.Partial("_Room", Model)
</div>

<br />

<button onclick="create()" >Create</button>
}
<script src="~/Scripts/jquery-1.8.2.min.js"></script>
<script src="~/Scripts/jquery.validate.min.js"></script>
<script src="~/Scripts/jquery.validate.unobtrusive.min.js"></script>

<script>
$(document).ready(function () {

    $(".create").removeAttr('required');
    $(".add-room").removeAttr('required');
});

function addRoom() {
    debugger;
    $(".add-room").removeAttr('required');
    $(".add-room").attr('required', true);

    var $valid = true;
    $('.add-room').each(function (i, obj) {
        var a = $(this).valid();
        if (!a) {
            $valid = a;
        }
    });

    if (!$valid) {
        return false;
    }
    else {

        var data = $("#commentForm").serializeArray();
        data.push({ name: 'Button', value: 'Add Room' });

        $.ajax({
            url: '@Url.Action("Create", "Building")',
            type: 'post',
            data: data,
            success: function (data) {
                debugger;
                $('#rooms').html(data);

                $(".add-room").removeAttr('required');
            },
            error: function (xhr, status, error) {
                debugger;
                alert(error);
            }
        });

    }
}

function create() {

    $(".add-room").removeAttr('required');
    $(".create").removeAttr('required');
    $(".create").attr('required', true);

    var $valid = true;
    $('.create').each(function (i, obj) {
        var a = $(this).valid();
        if (!a) {
            $valid = a;
        }
    });

    if (!$valid) {
        return false;
    }
    else {
        debugger;
        var data = $("#commentForm").serializeArray();
        data.push({ name: 'Button', value: 'Create' });

        $.ajax({
            url: '@Url.Action("Create", "Building")',
            type: 'post',
            data: data,
            success: function (data) {
                debugger;
                alert(data);
            },
            error: function (xhr, status, error) {
                debugger;
                alert(error);
            }
        });

    }
}
</script>

最后部分查看_Room.cshtml

@model Building

<fieldset>
<legend>Room</legend>

<div class="editor-label">
    @Html.LabelFor(model => model.NewRoom.RoomName)
</div>
<div class="editor-field">
    @Html.TextBoxFor(model => model.NewRoom.RoomName, htmlAttributes: new { @class = "add-room" })
    @Html.ValidationMessageFor(model => model.NewRoom.RoomName)
</div>

<div class="editor-label">
    @Html.LabelFor(model => model.NewRoom.Area)
</div>
<div class="editor-field">
    @Html.TextBoxFor(model => model.NewRoom.Area, htmlAttributes: new { @class = "add-room" })
    @Html.ValidationMessageFor(model => model.NewRoom.Area)
</div>

<p>
    <button onclick="addRoom();">Add Room</button>
</p>
</fieldset>

<br />
<table border="1" cellpadding="5px" cellspacing="0">
<thead>
    <tr>
        <th>#</th>
        <th>RoomName</th>
        <th>Area</th>
    </tr>
</thead>
<tbody>
    @for (int i = 0; i < Model.Rooms.Count(); i++)
    {
        <tr>
            <td>@(i + 1)</td>
            <td>@Model.Rooms[i].RoomName @Html.HiddenFor(t => Model.Rooms[i].RoomName)</td>
            <td>@Model.Rooms[i].Area @Html.HiddenFor(t => Model.Rooms[i].Area)</td>
        </tr>
    }
</tbody>
</table>

谢谢大家。