【问题标题】:How to get collection of IDs, and Selected Dropdown values passed from View's table to Controller?如何获取 ID 的集合,以及从 View 的表传递到 Controller 的 Selected Dropdown 值?
【发布时间】:2015-11-20 23:57:13
【问题描述】:

所以我有一个清单/任务管理器类型的应用程序,它基本上使用模型从数据库中提取一堆字符串值,然后通过管道将其输出到使用展开/折叠模式表的视图。最终用户在展开/折叠状态之外修改的唯一元素是项目状态的下拉列表。

客户基本上想要页面底部的一个按钮来更新用户更改的所有行,而不是每行的更新按钮。所以我的目标是尝试创建所述按钮。至于查看代码 sn-p,我尝试过使用 Html.BeginForm,但无法弄清楚如何同时捕获多个项目 ID:

@using (Html.BeginForm("UpdateDB", "Checklist", new { id = model.ID })) // model does not exist in this current context
{
<table id="checklistGrid" class="table table-bordered table-striped grid">
    <tr>
        <th>@Html.DisplayNameFor(model => model.ww)</th>
        .... // more table headers
    </tr>
    @foreach (var group in Model.GroupBy(x => x.ww))
        {
        <tr class="group-header">
            <td colspan="12">
                <span class="h2">@group.Key</span>
            </td>
        </tr>
        foreach (var dept in group.GroupBy(x => x.dept))
        {
            <tr class="dept-header">
                <td colspan="12">
                    <span class="h4">@dept.Key</span>
                </td>
            </tr>
            foreach (var item in dept)
            {
                <tr class="row-header">
                    <td> @Html.HiddenFor(modelItem => item.ID)</td>
                    <td>@Html.DisplayFor(modelItem => item.ww)</td>
                    .... // more table columns

                    <td>
                        @{
                            List<string> ddl = new List<string> { "Done", "Not Done", "N/A" };
                            SelectList sl = new SelectList(ddl, item.status);
                            @Html.DropDownList("newStatus", sl); // Added
                        }
                    </td>
                    <td>@Html.DisplayFor(modelItem => item.applied_by)</td>
                    <td>
                        @{
                            DateTime tmp;

                            //Check if not null, if not null convert to specified time zone
                            if (DateTime.TryParse(item.timestamp.ToString(), out tmp))
                            {
                                tmp = item.timestamp ?? DateTime.MinValue;

                                string zoneName = "India Standard Time";
                                var abbrZoneName = TimeZoneNames.TimeZoneNames.GetAbbreviationsForTimeZone(zoneName, "en-US");
                                TimeZoneInfo zoneInfo = TimeZoneInfo.FindSystemTimeZoneById(zoneName);
                                DateTime istTime = TimeZoneInfo.ConvertTimeFromUtc(tmp, zoneInfo);

                                @Html.Raw(istTime.ToString() + " (" + abbrZoneName.Generic + ")");
                            }
                            else
                            {
                                @Html.DisplayFor(modelItem => item.timestamp);
                            }
                        }
                    </td>
                </tr>
            }
        }
    }
</table>
<p><input type="submit" value="Save Changes" /></p>
}

<script type="text/javascript">
    // Hide/Show Dept's Data on Click
    $(function () {
        $('.dept-header').click(function () {
            $(this).nextUntil('.dept-header, .group-header').toggle();
        });
    });

    $(function () {
        $('.group-header').click(function () {
            var elm = $(this);
            if (elm.next().is(":visible")) {
                elm.nextUntil('.group-header').hide();
            } else {
                elm.nextUntil('.group-header', '.dept-header').show();
            }

        });
    });
</script>

我怀疑更简单(并且计算更快的方法)是使用附加到底部按钮 onclick 的 Jquery + Ajax && Json 将 id 和选定下拉文本的集合发送到 @987654323 中的 ActionResult @(然后更新数据库)然后刷新成功的 Ajax 回调。然而,我的 Jquery/Javascript foo 很弱,并且考虑到可点击的“标题”类型行展开/折叠数据行,我不清楚如何有效地使用 Jquery 导航和抓取 item.ID 以及从中选择的下拉文本将每一行捆绑起来,然后通过管道传递到所需的 ActionResult。

那么,如何将所有行的 id 和选定的下拉文本发送到任意 ActionResult,无论是 Html.BeginForm 还是 Jquery 等?

编辑:参考模型:

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity;
using System.Linq;
using System.Web;

namespace TaskTracker.Models
{
    [Table("some_update")]
    public class TaskInfo
    {
        public int ID { get; set; }

        [Display(Name = "WW")]
        public int ww { get; set; }

        [Display(Name = "File Name")]
        public string filename { get; set; }

        [Display(Name = "Dept")]
        public string hsd_unit { get; set; }

        [Display(Name = "Owner")]
        public string owner { get; set; }

        [Display(Name = "Manager")]
        public string manager { get; set; }

        [Display(Name = "Project")]
        public string project { get; set; }

        [Display(Name = "Status")]
        public string status { get; set; }

        [Display(Name = "Last Applied By")]
        public string applied_by { get; set; }

        [Display(Name = "Last Updated Time Stamp")]
        public DateTime? timestamp { get; set; }
    }

    public class TaskInfoDBContext : DbContext
    {
        public DbSet<TaskInfo> TaskInfoSet { get; set; }
    }
}

【问题讨论】:

  • 您不需要 javascript,除非您想留在同一页面上,否则 ajax 也不合适。您可以简单地发布表单并绑定到您的模型,但您当前的视图将无法正常工作,因为您使用 foreach 循环并因此生成与您的模型完全没有关系的重复 name 属性并重复 id无效的 html 属性。您需要使用for 循环或EditorTemplate。您需要展示您的模型才能更正此问题。
  • 抱歉延迟回复;模特张贴@StephenMuecke。

标签: javascript jquery html ajax asp.net-mvc


【解决方案1】:

您的视图存在许多问题,包括您的表单控件具有重复的 name 属性,这意味着您在提交时无法绑定到您的模型,重复的 id 属性是无效的 html,以及您使用甚至不是模型属性的名称。此外,您在视图代码中使用查询不是一个好习惯。所有这些都可以通过使用视图模型并使用for 循环(不是foreach 循环)或自定义EditorTemplate 正确生成您的html 来解决。但是,由于您已经表明了对 ajax 的偏好,您可以通过对视图进行以下更改来发布数据

替换以下 HtmlHelper 方法

@Html.HiddenFor(modelItem => item.ID)
@Html.DropDownList("newStatus", sl)

@Html.HiddenFor(modelItem => item.ID, new { id = "", @class = "id" })
@Html.DropDownList("Status", sl, new { id = "", @class = "status" })

这将删除无效的id 属性并添加类名以供选择。然后将提交按钮替换为

<button type="button" id="save">Save Changes</button>

并添加以下脚本

var rows = $('.row-header'); // store all the table rows containing the form controls
$('#save').click(function() {
  // Build an array of the values to post back
  var data = [];
  $.each(rows, function() {
    data.push({id: $(this).find('.id').val(), status: $(this).find('.status').val() });
  });
  $.ajax({
    url: '@Url.Action("UpdateDB", "Checklist")',
    type: "POST",
    data: JSON.stringify({ model: data },
    traditional: true,
    contentType: "application/json; charset=utf-8",
    success: function(data) {
      // do something?
    }
  })
});

然后创建一个模型来接受这些值

public class TaskInfoUpdate
{
  public int ID { get; set; }
  public string Status { get; set; }
}

并将您的 POST 方法修改为

[HttpPost]
public ActionResult UpdateDB(IEnumerable<TaskInfoUpdate> model)

旁注:不清楚您所说的“然后在成功的Ajax回调上刷新”(有什么要刷新的?)。如果项目成功保存,我建议该方法返回return Json(true);,否则返回return Json(null);(或HttpStatusCodeResult),以便您可以酌情通知用户。

【讨论】:

  • 我的偏好是最好的方法,基于仔细阅读类似的问题,人们倾向于评论 ajax 更好,因为它更快等,所以这就是为什么我费心提及它而不是请求仅使用的东西Html.BeginForm。但是,这很好用,当我以后有时间回去时,我可能会看看是否可以通过将 foreach 切换到 for 并添加 ViewModelDropDown 类型来使其工作允许绑定(我最初认为将每个项目从 DB 模型转换为 VM 太麻烦,但毕竟它可能是最干净的 OOD)
  • “最佳”方法取决于您在提交时要执行的操作。如果您想留在同一页面上并继续进行更改,请使用 ajax。如果要保存并重定向到另一个页面,请不要使用 ajax。请注意,我已回滚您的编辑。使用location.reload() 完全没有意义(它会重新加载您当前拥有的保存视图,使使用 ajax 毫无意义并降低性能)
猜你喜欢
  • 2019-08-24
  • 2023-03-07
  • 1970-01-01
  • 2019-06-15
  • 1970-01-01
  • 2018-07-22
  • 2013-07-15
  • 2020-02-17
  • 1970-01-01
相关资源
最近更新 更多