C# MVC 4 使用 Bootstrap 编辑模态表单

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/16011151/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-09 23:42:07  来源:igfitidea点击:

MVC 4 Edit modal form using Bootstrap

c#jqueryajaxasp.net-mvctwitter-bootstrap

提问by Traffy

I'm using MVC 4 and Entity Framework to develop an intranet web application. I have a list of persons which can be modify by an edit action. I wanted to make my app more dynamic by using modal forms. So I tried to put my edit view into my Bootstrap modal and I have 2 questions about it :

我正在使用 MVC 4 和实体框架来开发 Intranet Web 应用程序。我有一个可以通过编辑操作修改的人员列表。我想通过使用模态表单使我的应用程序更具动态性。所以我试图将我的编辑视图放入我的 Bootstrap 模式中,我有两个问题:

  • Should I use a simple or a partial view?
  • How can I perform the validation (actually it work but it redirects me to my original view so not in the modal form)
  • 我应该使用简单视图还是局部视图?
  • 我如何执行验证(实际上它可以工作,但它会将我重定向到我的原始视图,而不是在模态形式中)

I think I have to use AJAX and/or jQuery but I'm new to these technologies. Any help would be appreciated.

我想我必须使用 AJAX 和/或 jQuery,但我不熟悉这些技术。任何帮助,将不胜感激。

EDIT : My Index View :

编辑:我的索引视图:

@model IEnumerable<BuSIMaterial.Models.Person>

@{
    ViewBag.Title = "Index";
}


<h2>Index</h2>

<br />

<div class="group">
        <input type="button" value="New person" class="btn" onclick="location.href='@Url.Action("Create")';return false;"/>
        <input type="button" value="Download report" class="btn" onclick="location.href='@Url.Action("PersonReport")';return false;"/>
</div>


@using (Html.BeginForm("SelectedPersonDetails", "Person"))
{  
    <form class="form-search">
        <input type="text" id="tbPerson" name="tbPerson" placeholder="Find an employee..." class="input-medium search-query">
        <button type="submit" class="btn">Search</button>
    </form>
}


<table class="table">
    <thead>
        <tr>
            <th>Firstname</th>
            <th>Lastname</th>
            <th>Start Date</th>
            <th>End Date</th>
            <th>Details</th>
            <th>Actions</th>
        </tr>
    </thead>
    <tbody>
@foreach (BuSIMaterial.Models.Person item in ViewBag.PageOfPersons)
{
    <tr>
        <td>@item.FirstName</td>
        <td>@item.LastName</td>
        <td>@item.StartDate.ToShortDateString()</td>
        <td>
            @if (item.EndDate.HasValue)
            {
                @item.EndDate.Value.ToShortDateString()
            }        
        </td>

        <td>
            <a class="details_link" data-target-id="@item.Id_Person">Details</a>
        </td>

        <td>
            <div>
                <button class="btn btn-primary edit-person" data-id="@item.Id_Person">Edit</button>

            </div>
        </td>

    </tr>
    <tr>
        <td colspan="6">

            <table>
                <tr>
                    <th>National Number</th>
                    <td>@item.NumNat</td>
                </tr>
                <tr>
                    <th>Vehicle Category</th>
                    <td>@item.ProductPackageCategory.Name</td>
                </tr>
                <tr>
                    <th>Upgrade</th><td>@item.Upgrade</td>
                </tr>
                <tr>
                    <th>House to work</th>
                    <td>@item.HouseToWorkKilometers.ToString("G29")</td>
                </tr>
            </table>
            <div id="[email protected]_Person"></div>
        </td>

    </tr>

}
    </tbody>
</table>

<div class="modal hide fade in" id="edit-member">
    <div id="edit-person-container"></div>
</div>

@section Scripts
{
    @Scripts.Render("~/bundles/jqueryui")
    @Styles.Render("~/Content/themes/base/css")

    <script type="text/javascript" language="javascript">

        $(document).ready(function () {

            $('#tbPerson').autocomplete({
                source: '@Url.Action("AutoComplete")'
            });

            $(".details_link").click(function () {
                var id = $(this).data("target-id");
                var url = '/ProductAllocation/ListByOwner/' + id;
                $("#details_"+ id).load(url);
            });

            $('.edit-person').click(function () {
                var url = "/Person/EditPerson"; 
                var id = $(this).attr('data-id');
                $.get(url + '/' + id, function (data) {
                    $('#edit-person-container').html(data);
                    $('.edit-person').modal('show');
                });
            });


        });

    </script>
}

My Partial View :

我的部分观点:

@model BuSIMaterial.Models.Person

<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
    <h3 id="myModalLabel">Edit</h3>
</div>
<div>

@using (Ajax.BeginForm("EditPerson", "Person", FormMethod.Post,
                    new AjaxOptions
                    {
                        InsertionMode = InsertionMode.Replace,
                        HttpMethod = "POST",
                        UpdateTargetId = "list-of-people"
                    }))
{

    @Html.ValidationSummary()
    @Html.AntiForgeryToken()
    <div class="modal-body">
        <div class="editor-field">
            @Html.TextBoxFor(model => model.FirstName, new { maxlength = 50 })
            @Html.ValidationMessageFor(model => model.FirstName)
        </div>

        <div class="editor-field">
            @Html.TextBoxFor(model => model.LastName, new { maxlength = 50 })
            @Html.ValidationMessageFor(model => model.LastName)
        </div>
    </div>
    <div class="modal-footer">
        <button class="btn btn-inverse" type="submit">Save</button>
    </div>
}

采纳答案by MattSull

You should use partial views. I use the following approach:

您应该使用部分视图。我使用以下方法:

Use a view model so you're not passing your domain models to your views:

使用视图模型,这样您就不会将域模型传递给您的视图:

public class EditPersonViewModel
{
    public int Id { get; set; }   // this is only used to retrieve record from Db
    public string Name { get; set; }
    public string Age { get; set; }
}

In your PersonController:

在你的 PersonController:

[HttpGet] // this action result returns the partial containing the modal
public ActionResult EditPerson(int id)
{  
    var viewModel = new EditPersonViewModel();
    viewModel.Id = id;
    return PartialView("_EditPersonPartial", viewModel);
}

[HttpPost] // this action takes the viewModel from the modal
public ActionResult EditPerson(EditPersonViewModel viewModel)
{
    if (ModelState.IsValid)
    {
        var toUpdate = personRepo.Find(viewModel.Id);
        toUpdate.Name = viewModel.Name;
        toUpdate.Age = viewModel.Age;
        personRepo.InsertOrUpdate(toUpdate);
        personRepo.Save();
        return View("Index");
    }
}

Next create a partial view called _EditPersonPartial. This contains the modal header, body and footer. It also contains the Ajax form. It's strongly typed and takes in our view model.

接下来创建一个名为 的局部视图_EditPersonPartial。这包含模态页眉、正文和页脚。它还包含 Ajax 表单。它是强类型的并且接受我们的视图模型。

@model Namespace.ViewModels.EditPersonViewModel
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
    <h3 id="myModalLabel">Edit group member</h3>
</div>
<div>
@using (Ajax.BeginForm("EditPerson", "Person", FormMethod.Post,
                    new AjaxOptions
                    {
                        InsertionMode = InsertionMode.Replace,
                        HttpMethod = "POST",
                        UpdateTargetId = "list-of-people"
                    }))
{
    @Html.ValidationSummary()
    @Html.AntiForgeryToken()
    <div class="modal-body">
        @Html.Bootstrap().ControlGroup().TextBoxFor(x => x.Name)
        @Html.Bootstrap().ControlGroup().TextBoxFor(x => x.Age)
    </div>
    <div class="modal-footer">
        <button class="btn btn-inverse" type="submit">Save</button>
    </div>
}

Now somewhere in your application, say another partial _peoplePartial.cshtml etc:

现在在您的应用程序中的某个地方,说另一个部分 _peoplePartial.cshtml 等:

<div>
   @foreach(var person in Model.People)
    {
        <button class="btn btn-primary edit-person" data-id="@person.PersonId">Edit</button>
    }
</div>
// this is the modal definition
<div class="modal hide fade in" id="edit-person">
    <div id="edit-person-container"></div>
</div>

    <script type="text/javascript">
    $(document).ready(function () {
        $('.edit-person').click(function () {
            var url = "/Person/EditPerson"; // the url to the controller
            var id = $(this).attr('data-id'); // the id that's given to each button in the list
            $.get(url + '/' + id, function (data) {
                $('#edit-person-container').html(data);
                $('#edit-person').modal('show');
            });
        });
     });
   </script>

回答by Dmitry Efimenko

I prefer to avoid using Ajax.BeginFormhelper and do an Ajax call with JQuery. In my experience it is easier to maintain code written like this. So below are the details:

我更喜欢避免使用Ajax.BeginForm帮助程序并使用 JQuery 进行 Ajax 调用。根据我的经验,维护这样编写的代码更容易。所以下面是详细信息:

Models

楷模

public class ManagePeopleModel
{
    public List<PersonModel> People { get; set; }
    ... any other properties
}

public class PersonModel
{
    public int Id { get; set; }
    public string Name { get; set; }
    public int Age { get; set; }
    ... any other properties
}

Parent View

父视图

This view contains the following things:

该视图包含以下内容:

  • records of people to iterate through
  • an empty div that will be populated with a modal when a Person needs to be edited
  • some JavaScript handling all ajax calls
  • 要遍历的人的记录
  • 当一个人需要被编辑时,一个空的 div 将填充一个模态
  • 一些 JavaScript 处理所有 ajax 调用
@model ManagePeopleModel

<h1>Manage People</h1>

@using(var table = Html.Bootstrap().Begin(new Table()))
{
    foreach(var person in Model.People)
    {
        <tr>
            <td>@person.Id</td>
            <td>@Person.Name</td>
            <td>@person.Age</td>
            <td>@html.Bootstrap().Button().Text("Edit Person").Data(new { @id = person.Id }).Class("btn-trigger-modal")</td>
        </tr>
    }
}

@using (var m = Html.Bootstrap().Begin(new Modal().Id("modal-person")))
{

}

@section Scripts
{
    <script type="text/javascript">
        // Handle "Edit Person" button click.
        // This will make an ajax call, get information for person,
        // put it all in the modal and display it
        $(document).on('click', '.btn-trigger-modal', function(){
            var personId = $(this).data('id');
            $.ajax({
                url: '/[WhateverControllerName]/GetPersonInfo',
                type: 'GET',
                data: { id: personId },
                success: function(data){
                    var m = $('#modal-person');
                    m.find('.modal-content').html(data);
                    m.modal('show');
                }
            });
        });

        // Handle submitting of new information for Person.
        // This will attempt to save new info
        // If save was successful, it will close the Modal and reload page to see updated info
        // Otherwise it will only reload contents of the Modal
        $(document).on('click', '#btn-person-submit', function() {
            var self = $(this);
            $.ajax({
                url: '/[WhateverControllerName]/UpdatePersonInfo',
                type: 'POST',
                data: self.closest('form').serialize(),
                success: function(data) {
                    if(data.success == true) {
                        $('#modal-person').modal('hide');
                        location.reload(false)
                    } else {
                        $('#modal-person').html(data);
                    }
                }
            });
        });
    </script>
}

Partial View

局部视图

This view contains a modal that will be populated with information about person.

此视图包含一个模态,将填充有关人员的信息。

@model PersonModel
@{
    // get modal helper
    var modal = Html.Bootstrap().Misc().GetBuilderFor(new Modal());
}

@modal.Header("Edit Person")
@using (var f = Html.Bootstrap.Begin(new Form()))
{
    using (modal.BeginBody())
    {
        @Html.HiddenFor(x => x.Id)
        @f.ControlGroup().TextBoxFor(x => x.Name)
        @f.ControlGroup().TextBoxFor(x => x.Age)
    }
    using (modal.BeginFooter())
    {
        // if needed, add here @Html.Bootstrap().ValidationSummary()
        @:@Html.Bootstrap().Button().Text("Save").Id("btn-person-submit")
        @Html.Bootstrap().Button().Text("Close").Data(new { dismiss = "modal" })
    }
}

Controller Actions

控制器操作

public ActionResult GetPersonInfo(int id)
{
    var model = db.GetPerson(id); // get your person however you need
    return PartialView("[Partial View Name]", model)
}

public ActionResult UpdatePersonInfo(PersonModel model)
{
    if(ModelState.IsValid)
    {
        db.UpdatePerson(model); // update person however you need
        return Json(new { success = true });
    }
    // else
    return PartialView("[Partial View Name]", model);
}

回答by Max

In reply to Dimitrys answer but using Ajax.BeginFormthe following works at least with MVC >5 (4 not tested).

回复 Dimitrys 的回答,但使用Ajax.BeginForm以下内容至少适用于 MVC > 5(4 未测试)。

  1. write a model as shown in the other answers,

  2. In the "parent view" you will probably use a table to show the data. Model should be an ienumerable. I assume, the model has an id-property. Howeverm below the template, a placeholder for the modal and corresponding javascript

    <table>
    @foreach (var item in Model)
    {
        <tr> <td id="[email protected]"> 
            @Html.Partial("dataRowView", item)
        </td> </tr>
    }
    </table>
    
    <div class="modal fade" id="editor-container" tabindex="-1" 
         role="dialog" aria-labelledby="editor-title">
        <div class="modal-dialog modal-lg" role="document">
            <div class="modal-content" id="editor-content-container"></div>
        </div>
    </div> 
    
    <script type="text/javascript">
        $(function () {
            $('.editor-container').click(function () {
                var url = "/area/controller/MyEditAction";  
                var id = $(this).attr('data-id');  
                $.get(url + '/' + id, function (data) {
                    $('#editor-content-container').html(data);
                    $('#editor-container').modal('show');
                });
            });
        });
    
        function success(data,status,xhr) {
            $('#editor-container').modal('hide');
            $('#editor-content-container').html("");
        }
    
        function failure(xhr,status,error) {
            $('#editor-content-container').html(xhr.responseText);
            $('#editor-container').modal('show');
        }
    </script>
    
  1. 编写一个模型,如其他答案所示,

  2. 在“父视图”中,您可能会使用表格来显示数据。模型应该是一个可枚举的。我假设,该模型具有id- 属性。但是在模板下方,是模态和相应 javascript 的占位符

    <table>
    @foreach (var item in Model)
    {
        <tr> <td id="[email protected]"> 
            @Html.Partial("dataRowView", item)
        </td> </tr>
    }
    </table>
    
    <div class="modal fade" id="editor-container" tabindex="-1" 
         role="dialog" aria-labelledby="editor-title">
        <div class="modal-dialog modal-lg" role="document">
            <div class="modal-content" id="editor-content-container"></div>
        </div>
    </div> 
    
    <script type="text/javascript">
        $(function () {
            $('.editor-container').click(function () {
                var url = "/area/controller/MyEditAction";  
                var id = $(this).attr('data-id');  
                $.get(url + '/' + id, function (data) {
                    $('#editor-content-container').html(data);
                    $('#editor-container').modal('show');
                });
            });
        });
    
        function success(data,status,xhr) {
            $('#editor-container').modal('hide');
            $('#editor-content-container').html("");
        }
    
        function failure(xhr,status,error) {
            $('#editor-content-container').html(xhr.responseText);
            $('#editor-container').modal('show');
        }
    </script>
    

note the "editor-success-id" in data table rows.

注意数据表行中的“editor-success-id”。

  1. The dataRowViewis a partial containing the presentation of an model's item.

    @model ModelView
    @{
        var item = Model;
    }
    <div class="row">
            // some data 
            <button type="button" class="btn btn-danger editor-container" data-id="@item.Id">Edit</button>
    </div>
    
  2. Write the partial view that is called by clicking on row's button (via JS $('.editor-container').click(function () ...).

    @model Model
    <div class="modal-header">
        <button type="button" class="close" data-dismiss="modal" aria-label="Close">
            <span aria-hidden="true">&times;</span>
        </button>
        <h4 class="modal-title" id="editor-title">Title</h4>
    </div>
    @using (Ajax.BeginForm("MyEditAction", "Controller", FormMethod.Post,
                        new AjaxOptions
                        {
                            InsertionMode = InsertionMode.Replace,
                            HttpMethod = "POST",
                            UpdateTargetId = "editor-success-" + @Model.Id,
                            OnSuccess = "success",
                            OnFailure = "failure",
                        }))
    {
        @Html.ValidationSummary()
        @Html.AntiForgeryToken()
        @Html.HiddenFor(model => model.Id)
        <div class="modal-body">
            <div class="form-horizontal">
                // Models input fields
            </div>
        </div>
        <div class="modal-footer">
            <button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
            <button type="submit" class="btn btn-primary">Save</button>
        </div>
    }
    
  1. dataRowView是包含模型的项目的呈现部分。

    @model ModelView
    @{
        var item = Model;
    }
    <div class="row">
            // some data 
            <button type="button" class="btn btn-danger editor-container" data-id="@item.Id">Edit</button>
    </div>
    
  2. 编写通过单击行按钮(通过 JS $('.editor-container').click(function () ...)调用的局部视图。

    @model Model
    <div class="modal-header">
        <button type="button" class="close" data-dismiss="modal" aria-label="Close">
            <span aria-hidden="true">&times;</span>
        </button>
        <h4 class="modal-title" id="editor-title">Title</h4>
    </div>
    @using (Ajax.BeginForm("MyEditAction", "Controller", FormMethod.Post,
                        new AjaxOptions
                        {
                            InsertionMode = InsertionMode.Replace,
                            HttpMethod = "POST",
                            UpdateTargetId = "editor-success-" + @Model.Id,
                            OnSuccess = "success",
                            OnFailure = "failure",
                        }))
    {
        @Html.ValidationSummary()
        @Html.AntiForgeryToken()
        @Html.HiddenFor(model => model.Id)
        <div class="modal-body">
            <div class="form-horizontal">
                // Models input fields
            </div>
        </div>
        <div class="modal-footer">
            <button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
            <button type="submit" class="btn btn-primary">Save</button>
        </div>
    }
    

This is where magic happens: in AjaxOptions, UpdateTargetId will replace the data row after editing, onfailure and onsuccess will control the modal.

这就是神奇的地方:在 中AjaxOptions,UpdateTargetId 将在编辑后替换数据行,onfailure 和 onsuccess 将控制模式。

This is, the modal will only close when editing was successful and there have been no errors, otherwise the modal will be displayed after the ajax-posting to display error messages, e.g. the validation summary.

也就是说,只有在编辑成功并且没有错误时才会关闭模态,否则模态将在 ajax 发布后显示以显示错误消息,例如验证摘要。

But how to get ajaxform to know if there is an error? This is the controller part, just change response.statuscode as below in step 5:

但是如何让ajaxform知道是否有错误呢?这是控制器部分,只需在步骤 5 中更改 response.statuscode 如下:

  1. the corresponding controller action method for the partial edit modal

    [HttpGet]
    public async Task<ActionResult> EditPartData(Guid? id)
    {
        // Find the data row and return the edit form
        Model input = await db.Models.FindAsync(id);
        return PartialView("EditModel", input);
    }
    
    [HttpPost, ValidateAntiForgeryToken]
    public async Task<ActionResult> MyEditAction([Bind(Include =
       "Id,Fields,...")] ModelView input)
    {
        if (TryValidateModel(input))
        {  
            // save changes, return new data row  
            // status code is something in 200-range
            db.Entry(input).State = EntityState.Modified;
            await db.SaveChangesAsync();
            return PartialView("dataRowView", (ModelView)input);
        }
    
        // set the "error status code" that will redisplay the modal
        Response.StatusCode = 400;
        // and return the edit form, that will be displayed as a 
        // modal again - including the modelstate errors!
        return PartialView("EditModel", (Model)input);
    }
    
  1. 部分编辑模态对应的控制器动作方法

    [HttpGet]
    public async Task<ActionResult> EditPartData(Guid? id)
    {
        // Find the data row and return the edit form
        Model input = await db.Models.FindAsync(id);
        return PartialView("EditModel", input);
    }
    
    [HttpPost, ValidateAntiForgeryToken]
    public async Task<ActionResult> MyEditAction([Bind(Include =
       "Id,Fields,...")] ModelView input)
    {
        if (TryValidateModel(input))
        {  
            // save changes, return new data row  
            // status code is something in 200-range
            db.Entry(input).State = EntityState.Modified;
            await db.SaveChangesAsync();
            return PartialView("dataRowView", (ModelView)input);
        }
    
        // set the "error status code" that will redisplay the modal
        Response.StatusCode = 400;
        // and return the edit form, that will be displayed as a 
        // modal again - including the modelstate errors!
        return PartialView("EditModel", (Model)input);
    }
    

This way, if an error occurs while editing Model data in a modal window, the error will be displayed in the modal with validationsummary methods of MVC; but if changes were committed successfully, the modified data table will be displayed and the modal window disappears.

这样,如果在模态窗口中编辑Model数据时发生错误,错误会显示在MVC的validationsummary方法的模态中;但如果更改提交成功,则将显示修改后的数据表,并且模态窗口消失。

Note: you get ajaxoptions working, you need to tell your bundles configuration to bind jquery.unobtrusive-ajax.js(may be installed by NuGet):

注意:你让 ajaxoptions 工作,你需要告诉你的 bundles 配置绑定jquery.unobtrusive-ajax.js(可能由 NuGet 安装):

        bundles.Add(new ScriptBundle("~/bundles/jqueryajax").Include(
                    "~/Scripts/jquery.unobtrusive-ajax.js"));