Dynamically Add Form Elements in MVC3 Razor Create

2020-07-22 17:56发布

问题:

I'd like to create a form with a group of text boxes and every time a user clicks the add button those text boxes will be recreated as many time as the user clicks the add button. Here is a picture of what I am looking to do.

Controller:

    //
    // GET: /Client/MyMove/Create

    public ActionResult Create()
    {
        return View();
    }

    //
    // POST: /Client/MyMove/Create

    [HttpPost]
    public ActionResult Create(Move move)
    {
        var viewModel = new CreateMoveViewModel();
        MembershipUser currentUser = Membership.GetUser();
        Guid currentUserId = (Guid)currentUser.ProviderUserKey;
        if (ModelState.IsValid)
        {                
            move.UserId = currentUserId;
            db.Moves.Add(move);
            move.AddMoveItem(2);
            db.SaveChanges();
            return RedirectToAction("Index");
        }

        return View(move);
    }

Create.cshtml

@model MovinMyStuff.WebUI.Areas.Client.Models.CreateMoveViewModel
@using Telerik.Web.Mvc.UI
@{
    ViewBag.Title = "Create";
}

<h1>Post a Move</h1>

<script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript">    </script>
<script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>

@using (Html.BeginForm()) {
@Html.ValidationSummary(true)
<fieldset>
    <div class="form-item-group last">
        <div class="form-item half">
            <div class="editor-label">
                Start Date
            </div>
Editorfor for Model1...
    <div>
        @Html.Partial("_MoveItem")
    </div>
</fieldset>
<div class="submit-button-wrapper">
    <input class="button" type="submit" value="Post" />
</div>
}

<div>
    @Html.ActionLink("Go Back", "Index", null, new { @class = "link-text" })
</div>

ViewModel

namespace MovinMyStuff.WebUI.Areas.Client.Models
{
public class CreateMoveViewModel
{
    public CreateMoveViewModel()
    {
        Moves = new Move();
        MoveItems = new MoveItem();
    }
    public Move Moves { get; set; }
    public MoveItem MoveItems { get; set; }
}
}

Partial View

@model MovinMyStuff.Domain.Entities.MoveItem

    <div class="editor-label">
        Choose Area of Your Home
    </div>
    <div class="editor-field">
        @Html.EditorFor(model => model.MoveItemArea)
        @Html.ValidationMessageFor(model => model.MoveItemArea)
    </div>

    <div class="editor-label">
        Choose Your Item 
    </div>
    <div class="editor-field">
        @Html.EditorFor(model => model.MoveItemType)
        @Html.ValidationMessageFor(model => model.MoveItemType)
    </div>

    <div class="editor-label">
        Quantity
    </div>
    <div class="editor-field">
        @Html.EditorFor(model => model.Quantity)
        @Html.ValidationMessageFor(model => model.Quantity)
    </div>
Other Properties of model...


    <div class="editor-label">
        @Html.HiddenFor(model => model.MoveId)
    </div>

回答1:

I very strongly invite you to read the following article. It contains an example of how to achieve what you are looking for. It covers the challenges you will encounter with the default model binder when starting to implement this. To overcome those challenges with the collections indexes the author uses a custom Html.BeginCollectionItem helper.



回答2:

Well i will tried to create a partial View with the model that you need, The key will be to add the html generated from the partial view each time that click the button with ajax for example:

Your model

 public class example
 { 
     public int Length { get; set;}
     public int Width  { get; set;}
     public int Height {get; set;}
 }

Your Action

public ActionResult Example()
{
     return View();
}

Your Partial View

@model FooExample.Model.Example    

@{
     Layout = null;
 }

<div>
     @Html.EditorFor(model => model.Length)  
</div>
<div>
     @Html.EditorFor(model => model.Width)  
</div>
<div>
     @Html.EditorFor(model => model.Height)  
</div>

Your Principal View

<input type="button" id="btnAddRows" />

<table id="addViews">
     <tr>
        <td>
        </td> 
     </tr>
<table>

Now this is the script

$(document).ready(function(){
   $("#btnAddRows").click(function(){

       $.ajax({
            url: 'your path to the action',
            data : 'if you need to pass parameters',
            datatype: 'html',
            success: function(data){
               $("#addViews").append("<tr/><td>"+data+"</td><tr>");
           }  
       })

   });

});


回答3:

Here's an explanation to how I've implemented similar situations in the past: https://stackoverflow.com/a/10583792/1373170

Its more complicated since it required to support editing and deleting as well. The main idea is to have a hidden template (created with an EditorTemplate), used for creating new rows, and a bit of JavaScript to automatically name all new items to a way that will be automatically interpreted by MVC's default binder, and transformed to the appropriate List of ViewModels in the Action.