如何将项目列表从视图传递到控制器(ASP.NET MVC 4)

时间:2016-05-13 23:14:02

标签: c# jquery ajax asp.net-mvc linq

我尝试将列表< item> 类型的多个传递给我的控制器,但是,当我提交数据时,它显示为null我的控制员。

我希望发生的是我有一份费用列表'在视图中,以及每个费用旁边。或item是我的模型中已提交布尔属性的复选框。当我检查物品时,我想要检查物品清单'要在数据库中更新的已提交 DateSubmitted 属性。

视图中的

@ Html.DisplayFor(modelItem => item.Submitted)会生成复选框。

我做错了什么?

这是我的观点:

@model IEnumerable<Expenses.Models.Expense>

@{
ViewBag.Title = "Submit Expenses";
Layout = "~/Views/Shared/_Layout.cshtml";

DateTime today = DateTime.Today;
string formattedDate = today.ToString("MM/dd/yyyy");
}

<link rel="stylesheet" href="//code.jquery.com/ui/1.11.4/themes/smoothness/jquery-ui.css">
<script src="//code.jquery.com/jquery-1.10.2.js"></script>
<script src="//code.jquery.com/ui/1.11.4/jquery-ui.js"></script>

<h2>Submit Expenses</h2>

@using (Html.BeginForm())
{
@Html.AntiForgeryToken()
<div class="form-inline">
    <div class="form-group">
        <h4>Start Date:</h4>
        <div class="col-md-10">
            @Html.TextBox("expenseDate", formattedDate, htmlAttributes: new
           {
               @class = "form-control"
           })
        </div>
    </div>

    <div class="form-group">
        <h4>End Date:</h4>
        <div class="col-md-10">
            @Html.TextBox("expenseDate2", formattedDate, htmlAttributes: new
           {
               @class = "form-control"
           })
        </div>
    </div>

    <div class="form-group">
        @if (User.IsInRole("admin"))
        {
            <h4>Username:</h4>
            <div class="editor-field">
                @Html.DropDownList("UserId", String.Empty)
            </div>
        }
    </div>

    <br />
    <br />

    <div class="form-group">
        <div class="col-md-2">
            <input type="submit" value="Retrieve Expenses" class="btn btn-default" />
        </div>
    </div>

</div>

<br />
<br />


<p>
    @Html.ActionLink("Create New", "Create")
</p>
<table style="margin-bottom: 20px;">
    <tr>
        <th>
            @Html.DisplayNameFor(model => model.Company)
        </th>
        <th>
            @Html.DisplayNameFor(model => model.Category)
        </th>
        <th>
            @Html.DisplayNameFor(model => model.Province)
        </th>
        <th>
            @Html.DisplayNameFor(model => model.ReceiptName)
        </th>
        <th>
            @Html.DisplayNameFor(model => model.Comment)
        </th>
        <th>
            @Html.DisplayNameFor(model => model.GrossAmount)
        </th>
        <th>
            @Html.DisplayNameFor(model => model.TaxAmount)
        </th>
        <th>
            @Html.DisplayNameFor(model => model.NetAmount)
        </th>
        <th>
            @Html.DisplayNameFor(model => model.Mileage)
        </th>
        <th>
            @Html.DisplayNameFor(model => model.TravelStatus)
        </th>
        <th>
            @Html.DisplayNameFor(model => model.LunchLearnStatus)
        </th>
        <th>
            @Html.DisplayNameFor(model => model.WithClientStatus)
        </th>
        <th>
            @Html.DisplayNameFor(model => model.DateEntered)
        </th>
        <th>
            @Html.DisplayNameFor(model => model.DateSubmitted)
        </th>
        <th>
            @Html.DisplayNameFor(model => model.ExpenseDate)
        </th>
        <th>
            @Html.DisplayNameFor(model => model.ImageName)
        </th>
        @if (User.IsInRole("admin"))
        {
            <th>
                @Html.DisplayNameFor(model => model.UserProfile.UserName)
            </th>
        }
        <th></th>
    </tr>
    <tr>
        <td>
            <b>Select All:</b>
            <br />
            <input type="checkbox" name="expense" value="Expense" id="selectAllCheckboxes" class="expenseCheck">
        </td>
    </tr>
    @foreach (var item in Model)
    {
        <tr>
            <td class="submitCheck">
                @Html.EditorFor(modelItem => item.Submitted)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.Company)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.Category)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.Province)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.ReceiptName)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.Comment)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.GrossAmount)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.TaxAmount)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.NetAmount)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.Mileage)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.TravelStatus)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.LunchLearnStatus)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.WithClientStatus)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.DateEntered)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.DateSubmitted)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.ExpenseDate)
            </td>
            <td>
                @if (item.ImageName != null)
                {
                    <a href="~/Images/@Html.DisplayFor(modelItem => item.UserProfile.FullName)/@Html.DisplayFor(modelItem => item.ImageName)" class="imageClick" target="_blank"><img src="~/Images/@Html.DisplayFor(modelItem => item.UserProfile.FullName)/@Html.DisplayFor(modelItem => item.ImageName)" alt="Image" style="width:80%" /></a>
                }
            </td>
            @if (User.IsInRole("admin"))
            {
                <td>
                    @Html.DisplayFor(modelItem => item.UserProfile.UserName)
                </td>
            }
            <td>
                @Html.ActionLink("Edit", "Edit", new { id = item.ExpenseId }) |
                @Html.ActionLink("Details", "Details", new { id = item.ExpenseId }) |
                @if (User.IsInRole("admin"))
                {
                    @Html.ActionLink("Delete", "Delete", new { id = item.ExpenseId })
                }

            </td>
        </tr>
    }

</table>

 @Html.ActionLink("Submit Expenses", "SubmitExpenses", "Expenses", null, new { @class = "submitLink", @style = "background-color: #d3dce0; border: 1px solid #787878; cursor: pointer; font-size: 1.5em; font-weight: 600; margin-right: 8px; padding: 7px; width: auto; text-decoration: none; font-weight:bold;"})

<div class="ExportSection" style="margin-top:30px;">
    @*<a href="javascript:void(0)">Export To CSV</a>*@
    @Html.ActionLink("Export To CSV", "ExportExpensesListToCSV")
</div>
}

@section scripts {
<script type="text/javascript">


    $("#selectAllCheckboxes").click(function () {
        $('.submitCheck input:checkbox').not(this).prop('checked', this.checked);
    });

    $(function () {
        $("#expenseDate").datepicker();
    });

    $(function () {
        $("#expenseDate2").datepicker();
    });

</script>

}

这是我的Controller方法:

public ActionResult SubmitExpenses(List<Expense> expenses, DateTime? expenseDate = null, DateTime? expenseDate2 = null, int? userId = 0)
    {
        expenseDate = (DateTime)Session["FirstDate"];
        expenseDate2 = (DateTime)Session["SecondDate"];

        if (expenseDate == null || expenseDate2 == null)
        {
            expenseDate = DateTime.Now.AddMonths(-1);
            expenseDate2 = DateTime.Today;
        }

        string currentUserId = User.Identity.Name;

        var query = from e in db.Expenses
                    join user in db.UserProfiles on e.UserId equals user.UserId
                    where e.ExpenseDate >= expenseDate && e.ExpenseDate <= expenseDate2 && e.DateSubmitted == null
                    orderby e.ExpenseDate descending
                    select new { e, user };

        if (User.IsInRole("admin") && userId != 0)
        {
            query = query.Where(x => x.user.UserId == userId);
        }
        else if (!User.IsInRole("admin"))
        {
            query = query.Where(x => x.user.UserName == currentUserId);
        }

        var expensesFromView = expenses;

        var joined = from dbExpense in query.Select(x => x.e).AsEnumerable()
                     join localExpense in expenses on dbExpense.ExpenseId equals localExpense.ExpenseId
                     where localExpense.Submitted
                     select dbExpense;

        foreach (Expense exp in joined)
        {
            exp.DateSubmitted = DateTime.Today;
        }

        try
        {
            db.SaveChanges();
            return RedirectToAction("Index");
        }
        catch (Exception e)
        {
            Console.WriteLine(e);
            return RedirectToAction("Submit");
        }

    }

这是我的模特:

[Key]
    [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
    public int ExpenseId { get; set; }

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

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

    [Required]
    [Display(Name = "Receipt Name")]
    public string ReceiptName { get; set; }
    public string Comment { get; set; }

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

    [Required]
    [Display(Name = "Gross Amount")]
    public decimal GrossAmount { get; set; }

    [Required]
    [Display(Name = "GST/HST Amount")]
    public decimal TaxAmount { get; set; }

    [Required]
    [Display(Name = "Net Amount")]
    public decimal NetAmount { get; set; }

    [Display(Name = "Mileage (in Kilometers)")]
    public int Mileage { get; set; }

    [Display(Name = "Travelling?")]
    public bool TravelStatus { get; set; }

    [Display(Name = "Lunch & Learn?")]
    public bool LunchLearnStatus { get; set; }

    [Display(Name = "With Clients?")]
    public bool WithClientStatus { get; set; }

    [DisplayFormat(DataFormatString = "{0:MM/dd/yyyy}")]
    [Required]
    [Display(Name = "Date Entered")]
    public DateTime? DateEntered{ get; set; }

    [DisplayFormat(DataFormatString = "{0:MM/dd/yyyy}")]
    [Display(Name = "Date Submitted")]
    public DateTime? DateSubmitted { get; set; }

    [DisplayFormat(DataFormatString = "{0:MM/dd/yyyy}")]
    [Required]
    [Display(Name = "Expense Date")]
    public DateTime? ExpenseDate { get; set; }

    [Display(Name = "Image")]
    public string ImageName { get; set; }

    [Display(Name = "Submitted?")]
    public bool Submitted { get; set; }

    [Required]
    [Display(Name = "Name")]
    public int UserId { get; set; }
    [ForeignKey("UserId")]
    public virtual UserProfile UserProfile { get; set; }

我的变量expensesFromView显示为空,因此,我的joined查询出现错误:

  

值不能为空。参数名称:内部

3 个答案:

答案 0 :(得分:3)

有两种方法可以做到这一点 -

1。

  

您可能需要这个非常好且可扩展的扩展 -   MvcCheckBoxList - 看到此网站已关闭:)请参阅选项2

2。

@for (int i = 0; i < Model.Count; i++)
{

     <tr>
      <td class="submitCheck">
       <input type="checkbox" value="@Model[i].Id" name="Expense[@i].Id">
       <input type="hidden" value="0" name="Expense[@i].Id">          
      </td>
      <td>
          @Html.DisplayFor(modelItem => item.Company)
      </td>
     </tr>
}

btw:如果你使用第二种方式:在你的控制器中,过滤费用对象的Id的零值;如果没有被选中,则将零发送到控制器(作为元素的ID),以便在上面的代码中看到“隐藏”字段。

答案 1 :(得分:2)

我无法找到直接从View传递给项目列表的方法,所以我决定使用AJAX。

我将控制器的参数从列表&lt;&gt; 类型更改为 int [] ,以获取项目ID数组:

public ActionResult SubmitExpenses(int[] expenseIDs, DateTime? expenseDate = null, DateTime? expenseDate2 = null, int? userId = 0)
    {
        expenseDate = (DateTime)Session["FirstDate"];
        expenseDate2 = (DateTime)Session["SecondDate"];

        if (expenseDate == null || expenseDate2 == null)
        {
            expenseDate = DateTime.Now.AddMonths(-1);
            expenseDate2 = DateTime.Today;
        }

        string currentUserId = User.Identity.Name;

        var query = from e in db.Expenses
                    join user in db.UserProfiles on e.UserId equals user.UserId
                    where e.ExpenseDate >= expenseDate && e.ExpenseDate <= expenseDate2 && e.DateSubmitted == null
                    orderby e.ExpenseDate descending
                    select new { e, user };

        if (User.IsInRole("admin") && userId != 0)
        {
            query = query.Where(x => x.user.UserId == userId);
        }
        else if (!User.IsInRole("admin"))
        {
            query = query.Where(x => x.user.UserName == currentUserId);
        }

        //var localExpenseIDs = expenseIDs;

        var joined = from dbExpense in query.Select(x => x.e).AsEnumerable()
                     join localExpense in expenseIDs on dbExpense.ExpenseId equals localExpense
                     where localExpense == dbExpense.ExpenseId
                     select dbExpense;

        foreach (Expense exp in joined)
        {
            exp.DateSubmitted = DateTime.Today;
            exp.IsSubmitted = true;
        }

        try
        {
            db.SaveChanges();
            return RedirectToAction("Index");
        }
        catch (Exception e)
        {
            Console.WriteLine(e);
            return RedirectToAction("Submit");
        }

    }

在我看来,我将每个项目的ID分配给它自己的HTML复选框:

@foreach (var item in Model)
    {
        <tr>
            <td class="checkbox-td">
                @Html.CheckBox("isSubmitted", new
           {
               @id = @Html.DisplayFor(modelItem => item.ExpenseId),
               @class = "submitBox"
           })
            </td>
        </tr>
     }

<div>
    @Html.ActionLink("Submit Expenses", "", "", null, new { @id = "submitExpensesLink" })
</div>

我编写了一些jQuery,因此每个选中的复选框都会将input元素的id添加到数组中,整数数组将 POST 添加到 SubmitExpenses 行动:

var checkedArray = [];

    $(':checkbox[name=isSubmitted]').on('change', function () {

        checkedArray = $(':checkbox[name=isSubmitted]:checked').map(function () {
                return this.id;
         })
        .get();


        //alert(checkedArray);
    });

    $('#submitExpensesLink').click(function () {

        $.ajax({
            type: "POST",
            traditional: true,
            url: "@Url.Action("SubmitExpenses", "Expenses")",
            data: { expenseIDs: checkedArray },
        success: function () {
            alert("Success!");
        },
        error: function (XMLHttpRequest, textStatus, errorThrown) {
            if (debug) {
                alert(XMLHttpRequest.responseText);
                alert(textStatus);
                alert(errorThrown);
            }
        }
    });
    })

答案 2 :(得分:0)

1)将FormMethod.Post添加到@using (Html.BeginForm()) {}

@using (Html.BeginForm("nameAction", "nameController", FormMethod.Post))
{
   //Your  code
}

2)你应该为这样的输入添加名称:

<input type="text" name="someName"/>