簡體   English   中英

ASP.NET MVC Core 2.0中多個記錄的表數據條目

[英]Table data entry for multiple records in ASP.NET MVC Core 2.0

我正在構建一個應用程序,我的應用程序的一個要求是,當用戶必須創建每個事務的卷時,用戶希望能夠在單擊保存之前放置多個事務,因此用戶可以選擇向表(使用javascript)。 以下是我所談論的圖像。

在此輸入圖像描述

我的View有一個名為VolumeConfigModel和ConfigItem的類,其代碼如下:

public class VolumenConfigViewModel
{
    public int CompanyId { get; set; }

    public string CompanyName { get; set; }

    public List<ConfigItem> Configurations { get; set; }

}

public class ConfigItem
{
    public int TranTypeId { get; set; }
    public int MaxVolume { get; set; }
    public int PaymentId { get; set; }
}

我的Add.cshtml文件如下所示:

@model IEnumerable<VolumenConfigViewModel>
<form id="addVolConfig" asp-controller="Volumen" asp-action="Add" role="form" method="post">
<div asp-validation-summary="All" class="text-danger"></div>
<input type="hidden" asp-for="@Model.CompanyId" />
<div><span>Configurations for Company @Model.CompanyName</span></div>
<table class="table" id="tblConfig" name="tblConfig">
    <thead>
        <tr>
            <th>
                Tran Type
            </th>
            <th>
                Payment Type
            </th>
            <th>
                Max Vol
            </th>
        </tr>
    </thead>
    <tbody>
        @foreach (var grd in Model.Configurations)
        {
            <tr>
                <td>

                    @Html.DropDownListFor(modelItem => grd.TranTypeId, (IEnumerable<SelectListItem>)ViewBag.TranTypes, "Please select", new { @class = "form-control" })
                </td>
                <td>
                    @Html.DropDownListFor(modelItem => grd.PaymentId, (IEnumerable<SelectListItem>)ViewBag.Payments, "Please select", new { @class = "form-control" })
                </td>
                <td>
                    @Html.EditorFor(modelItem => grd.MaxVolume)
                </td>
            </tr>
        }
    </tbody>
</table>

這是我的兩個問題:

  1. 每次用戶單擊“添加行”時,如何添加新行?
  2. 如何將信息作為列表發送回Controller?

對不起,我問了兩個問題,但兩者都是同一個問題。

非常感謝你對此的幫助。

MVC綁定器將使用name將數據綁定回模型,因此如果你輸入像Configurations [0] .TranType這樣的名稱,它將作為列表發回。 您可以使用以下擴展方法來實現這一點

這個是下拉列表

/// Custom helper to return select element for each property in the object that is represented by the expression and element is made disabled depending on the give input
    /// This SubDropDownListFor is used to generate DDropdown IDs fully compatible with ModelBinder when submitting a list of items.
    /// </summary>
    /// <typeparam name="TModel"></typeparam>
    /// <typeparam name="TProperty"></typeparam>
    /// <param name="htmlHelper"></param>
    /// <param name="expression"></param>
    /// <param name="selectList"></param>
    /// <param name="elementIndex"></param>
    /// <param name="optionLabel"></param>
    /// <param name="htmlAttributes"></param>
    /// <param name="isReadOnly"></param>
    /// <returns></returns>
    public static MvcHtmlString SubDropDownListFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, SelectList selectList,int elementIndex, string optionLabel = null, object htmlAttributes = null, bool isReadOnly = false)
    {
        var attrs = HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes);
        if (isReadOnly)
        {
            attrs.Add("disabled", "disabled");
        }
        Func<TModel, TProperty> method = expression.Compile();
        TProperty prop = method(htmlHelper.ViewData.Model);
        var dropdownName = ExpressionHelper.GetExpressionText(expression);
        dropdownName = dropdownName.Substring(dropdownName.LastIndexOf('.') + 1);
        Regex r = new Regex(@"^.*?\(.*\)\.Model\.(?<par1>.*?)\.ElementAt.*\)\.(?<par2>.*?)$");
        MatchCollection mcKVPs = r.Matches(expression.Body.Reduce().ToString());
        var kvps = from Match m in mcKVPs
                   where mcKVPs != null
                   where mcKVPs.Count > 0
                   select new
                   {
                       val1 = m.Groups["par1"].Value,
                       val2 = m.Groups["par2"].Value
                   };
        var kvp = kvps.FirstOrDefault();
        var selectTag = new TagBuilder("select");
        var metaData = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData);
        var displayname = metaData.DisplayName.IsNull() ? dropdownName : metaData.DisplayName;
        if (kvp.IsNotNull())
        {
            selectTag.Attributes["id"] = kvp.val1 + "_" + elementIndex + "_" + kvp.val2;
            selectTag.Attributes["name"] = kvp.val1 + "[" + elementIndex + "]." + kvp.val2;
        }
        else
        {
            selectTag.Attributes["id"] = attrs["id"].IsNotNull() ? attrs["id"].ToString() : elementIndex+"_"+dropdownName;
            selectTag.Attributes["name"] = attrs["name"].IsNotNull() ? attrs["name"].ToString() : "[" + elementIndex + "]." + dropdownName;
        }
        StringBuilder builder = new StringBuilder().AppendLine();
        if (optionLabel != null)
        {
            builder.AppendLine(ListItemToOption(new SelectListItem { Text = optionLabel, Value = "" }));
        }
        if (selectList != null)
        {
            foreach (var item in selectList)
            {
                builder.AppendLine(ListItemToOption(item, prop.ToCString()));
            }
        }
        selectTag.InnerHtml = builder.ToString();
        selectTag.MergeAttributes(attrs);
        return new MvcHtmlString(selectTag.ToString(TagRenderMode.Normal));

    }
    private static string ListItemToOption(SelectListItem item,string selected=null)
    {
        TagBuilder builder = new TagBuilder("option")
        {
            InnerHtml = HttpUtility.HtmlEncode(item.Text)
        };
        if (item.Value != null)
        {
            builder.Attributes["value"] = item.Value;
        }
        if (item.Value == selected)
        {
            builder.Attributes["selected"] = "selected";
        }
        return builder.ToString(TagRenderMode.Normal);
    }

這是用於文本框的

 /// <summary>
    ///  Custom helper to return text element for each property in the object thet is represented by the expression and element is made read only depending on the give input
    ///  This SubtextboxFor is used to generate TextBox IDs fully compatible with ModelBinder when submitting a list of items.
    ///  Note:it applys a readonly class to the element make sure you have a class named "readOnly"
    /// Also if you want to format you can use the System.ComponentModel.DataAnnotations.DataType and DisplayFormat to define the datatype and its format.
    /// </summary>
    /// <typeparam name="TModel"></typeparam>
    /// <typeparam name="TProperty"></typeparam>
    /// <param name="htmlHelper"></param>
    /// <param name="expression"></param>
    /// <param name="elementIndex"></param>
    /// <param name="htmlAttributes"></param>
    /// <param name="isReadOnly"></param>
    /// <returns></returns>
    /// <example>
    /// <code>
    /// <![CDATA[ consider Model is IEnumerable<Client> @for (int i = 0; i < Model.Products.Count(); i++) { @Html.SubTextBoxFor(modelItem => Model.Products.ElementAt.ProductDetailsID,i) } output textbox name is Client.Products[i].ProductDetailsID which allows modelbinder to bind it properly  ]]>
    /// </code>
    /// </example>
    public static MvcHtmlString SubTextBoxFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, int elementIndex, object htmlAttributes = null, bool? isReadOnly = null)
    {
        var attrs = HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes);
        if (isReadOnly ?? false)
        {
            if (attrs.ContainsKey("class"))
                attrs["class"] = attrs["class"] + " readOnly";
            else
                attrs.Add("class", "readOnly");
            attrs.Add("readonly", "readonly");
        }
        Func<TModel, TProperty> method = expression.Compile();
        TProperty val = method(htmlHelper.ViewData.Model);
        var textboxName = ExpressionHelper.GetExpressionText(expression);
        textboxName = textboxName.Substring(textboxName.LastIndexOf('.') + 1);
        Regex r = new Regex(@"^.*?\(.*\)\.Model\.(?<par1>.*?)\.ElementAt.*\)\.(?<par2>.*?)$");
        MatchCollection mcKVPs = r.Matches(expression.Body.Reduce().ToString());
        var kvps = from Match m in mcKVPs
                   where mcKVPs != null
                   where mcKVPs.Count > 0
                   select new
                   {
                       val1 = m.Groups["par1"].Value,
                       val2 = m.Groups["par2"].Value
                   };
        var kvp = kvps.FirstOrDefault();
        var inputTag = new TagBuilder("input");
        var metaData = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData);
        var displayname = metaData.DisplayName.IsNull() ? textboxName : metaData.DisplayName;
        if (kvp.IsNotNull())
        {
            inputTag.Attributes["id"] = kvp.val1 +"_"+ elementIndex +"_"+ kvp.val2;
            inputTag.Attributes["name"] = kvp.val1 + "[" + elementIndex + "]." + kvp.val2;
        }
        else
        {
            inputTag.Attributes["id"] = attrs["id"].IsNotNull() ? attrs["id"].ToString() : elementIndex + "_" + textboxName;
            inputTag.Attributes["name"] = attrs["name"].IsNotNull() ? attrs["name"].ToString() : "[" + elementIndex.ToString() + "]." + textboxName;
        }
        inputTag.Attributes["type"] = "text";
        switch (metaData.DataTypeName)
        {
            case "Currency":
                inputTag.Attributes["value"] = val.IsNotNull() ? Convert.ToDouble(val).ToString(metaData.DisplayFormatString) : string.Empty;
                break;
            case "Date":
            case "DateTime":
                inputTag.Attributes["value"] = val.IsNotNull() ? val.ToDateTime().ToString(metaData.DisplayFormatString) : string.Empty;
                break;
            default:
                inputTag.Attributes["value"] = val.IsNotNull() ? val.ToString() : string.Empty;
                break;
        }
        inputTag.Attributes["value"] = val.IsNotNull() ? val.ToString() : "";
        inputTag.MergeAttributes(attrs);
        return new MvcHtmlString(inputTag.ToString(TagRenderMode.Normal));
    }

這適用於像Ids這樣的隱藏字段

/// <summary>
    /// Custom helper to return input hidden element for each property in the object that is represented by the expression and element is made disabled depending on the give input
    /// This SubHiddenFor is used to generate hiddenfield IDs fully compatible with ModelBinder when submitting a list of items.
    /// </summary>
    /// <typeparam name="TModel"></typeparam>
    /// <typeparam name="TProperty"></typeparam>
    /// <param name="htmlHelper"></param>
    /// <param name="expression"></param>
    /// <param name="elementIndex"></param>
    /// <param name="htmlAttributes"></param>
    /// <returns></returns>
    public static MvcHtmlString SubHiddenFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression,int elementIndex, object htmlAttributes=null)
    {
        var attrs = HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes);

        Func<TModel, TProperty> method = expression.Compile();
        TProperty val = method(htmlHelper.ViewData.Model);
        var hiddenfieldName = ExpressionHelper.GetExpressionText(expression);
        hiddenfieldName = hiddenfieldName.Substring(hiddenfieldName.LastIndexOf('.') + 1);
        Regex r = new Regex(@"^.*?\(.*\)\.Model\.(?<par1>.*?)\.ElementAt.*\)\.(?<par2>.*?)$");
        MatchCollection mcKVPs = r.Matches(expression.Body.Reduce().ToString());
        var kvps = from Match m in mcKVPs
                   where mcKVPs != null
                   where mcKVPs.Count > 0
                   select new
                   {
                       val1 = m.Groups["par1"].Value,
                       val2 = m.Groups["par2"].Value
                   };
        var kvp = kvps.FirstOrDefault();
        var inputTag = new TagBuilder("input");
        var metaData = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData);
        var displayname = metaData.DisplayName.IsNull() ? hiddenfieldName : metaData.DisplayName;
        if (kvp.IsNotNull())
        {
            inputTag.Attributes["id"] = kvp.val1 +"_"+ elementIndex +"_"+ kvp.val2;
            inputTag.Attributes["name"] = kvp.val1 + "[" + elementIndex + "]." + kvp.val2;
        }
        else
        {
            inputTag.Attributes["id"] = attrs["id"].IsNotNull() ? attrs["id"].ToString() : elementIndex+"_"+hiddenfieldName;
            inputTag.Attributes["name"] = attrs["name"].IsNotNull() ? attrs["name"].ToString() : "[" + elementIndex + "]." + hiddenfieldName;
        }
        inputTag.Attributes["type"] = "hidden";
        inputTag.Attributes["value"] = val.ToCString();
        inputTag.MergeAttributes(attrs);
        return new MvcHtmlString(inputTag.ToString(TagRenderMode.Normal));
    }

這是復選框

/// <summary>
    /// Custom helper to return input type checkbox with a label element for each property in the object that is represented by the expression
    /// This SubCheckBoxWithLabel is used to generate input type checkboxes IDs fully compatible with ModelBinder when submitting a list of items.
    /// </summary>
    /// <typeparam name="TModel"></typeparam>
    /// <param name="htmlHelper"></param>
    /// <param name="expression"></param>
    /// <param name="elementIndex"></param>
    /// <param name="htmlLabelAttributes"></param>
    /// <param name="htmlCheckBoxAttributes"></param>
    /// <returns></returns>
    public static MvcHtmlString SubCheckBoxWithLabel<TModel>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, bool>> expression, int elementIndex, object htmlLabelAttributes = null, object htmlCheckBoxAttributes = null)
    {
        var attrs = HtmlHelper.AnonymousObjectToHtmlAttributes(htmlCheckBoxAttributes);

        Func<TModel, bool> method = expression.Compile();
        bool? val = method(htmlHelper.ViewData.Model);
        var chkattrs = HtmlHelper.AnonymousObjectToHtmlAttributes(htmlCheckBoxAttributes);
        var checkboxName = ExpressionHelper.GetExpressionText(expression);
        var checkboxID = ExpressionHelper.GetExpressionText(expression);
        var hiddenTag = new TagBuilder("input");
        checkboxName = checkboxName.Substring(checkboxName.LastIndexOf('.') + 1);
        var metadata = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData);
        var displayname = metadata.DisplayName.IsNull() ? checkboxName : metadata.DisplayName;
        checkboxName = "[" + elementIndex + "]." + checkboxName;
        checkboxID = checkboxID.Replace('.', '_') + "_" + elementIndex;
        Regex r = new Regex(@"^.*?\(.*\)\.Model\.(?<par1>.*?)\.ElementAt.*\)\.(?<par2>.*?)$");
        MatchCollection mcKVPs = r.Matches(expression.Body.Reduce().ToString());
        var kvps = from Match m in mcKVPs
                   where mcKVPs != null
                   where mcKVPs.Count > 0
                   select new
                   {
                       val1 = m.Groups["par1"].Value,
                       val2 = m.Groups["par2"].Value
                   };
        var kvp = kvps.FirstOrDefault();
        var labelTag = new TagBuilder("label");
        var CheckboxTag = new TagBuilder("input");


        if (kvp.IsNotNull())
        {
            CheckboxTag.Attributes["id"] = "chk" + kvp.val1 + elementIndex + kvp.val2;
            CheckboxTag.Attributes["name"] = "chk" + kvp.val1 + "[" + elementIndex + "]." + kvp.val2;
            hiddenTag.Attributes["id"] = kvp.val1 + elementIndex + kvp.val2;
            hiddenTag.Attributes["name"] = kvp.val1 + "[" + elementIndex + "]." + kvp.val2;
        }
        else
        {
            CheckboxTag.Attributes["id"] = "chk" + (attrs["id"].IsNotNull() ? attrs["id"].ToString() : checkboxID);
            CheckboxTag.Attributes["name"] = "chk" + (attrs["name"].IsNotNull() ? attrs["name"].ToString() : checkboxName);
            hiddenTag.Attributes["id"] = attrs["id"].IsNotNull() ? attrs["id"].ToString() : checkboxID;
            hiddenTag.Attributes["name"] = attrs["name"].IsNotNull() ? attrs["name"].ToString() : checkboxName;
        }
        hiddenTag.Attributes["type"] = "hidden";
        CheckboxTag.Attributes["type"] = "checkbox";
        CheckboxTag.MergeAttribute("onclick", "javascript: $(this).parent().next('#" + hiddenTag.Attributes["id"] + "').val($(this).is(':checked'));");
        CheckboxTag.Attributes["value"] = val.ToString().ToLower();
        hiddenTag.Attributes["value"] = val.ToString().ToLower();
        if (val == true)
        {
            CheckboxTag.Attributes["checked"] = "checked";
        }
        CheckboxTag.MergeAttributes(HtmlHelper.AnonymousObjectToHtmlAttributes(htmlCheckBoxAttributes));
        labelTag.AddCssClass("checkbox");
        labelTag.MergeAttributes(HtmlHelper.AnonymousObjectToHtmlAttributes(htmlLabelAttributes));
        labelTag.InnerHtml = MvcHtmlString.Create(CheckboxTag.ToString(TagRenderMode.SelfClosing)) + "&nbsp;" + displayname;

        return new MvcHtmlString(labelTag.ToString() + hiddenTag.ToString(TagRenderMode.SelfClosing));
    }

要使用它,你需要編碼你的cshtml如下

 @for (int i = 0; i < Model.Count(); i++)
{
    <tr id="dvUser-@i">
        <td>
            @Html.SubHiddenFor(modelItem=>Model.ElementAt(i).Id,i)
            @Html.SubTextBoxFor(modelItem => Model.ElementAt(i).UserName, i, new { @class="form-control" })
        </td>
        <td>
            @Html.SubPasswordFor(modelItem => Model.ElementAt(i).NewPassword, i, new { @class="form-control" })
        </td>
        <td>
            @Html.SubDropDownListFor(modelItem => Model.ElementAt(i).RoleId,(SelectList)ViewBag.Roles, i,"Select", new { @class = "form-control" })
        </td>

    </tr>
}

我想你應該試試這樣的事情

@{
    int i = 0;
    foreach (var grd in Model.Configurations)
    {
        <tr>
            <td>

                @Html.DropDownListFor(modelItem => grd.TranTypeId, (IEnumerable<SelectListItem>)ViewBag.TranTypes, "Please select", new { @id = "TranTypeId_"+i, @class = "form-control" })
            </td>
            <td>
                @Html.DropDownListFor(modelItem => grd.PaymentId, (IEnumerable<SelectListItem>)ViewBag.Payments, "Please select", new { @id = "PaymentId_"+i, @class = "form-control" })
            </td>
            <td>
                @Html.EditorFor(modelItem => grd.MaxVolume,new { @id = "MaxVolume_"+i })
            </td>
        </tr>
        i++;
    }
}

要添加新行,請參閱此示例https://www.c-sharpcorner.com/article/pass-dynamically-added-html-table-records-list-to-controller/

https://patricjsson.wordpress.com/2015/05/25/asp-net-mvc-proper-model-binding-with-dynamic-form/

如果您不想刷新頁面,可以使用ajax-form選項。

<div id="ajaxContent">
  <form asp-antiforgery="true" data-ajax="true" data-ajax-method="post" data-ajax-update="#ajaxContent" data-ajax-mode="REPLACE-WITH">
    <button type="submit" asp-page-handler="Ajax">Add Person</button>

    <!--Form Content-->

  </form>
</div>

請注意data-ajax- *選項和對#ajaxContent的更新引用。 此外,提交按鈕與處理程序Ajax

如果您想將ajax響應僅限於表單內容,則無法將no ajax內容包裝到IsAjaxRequest()中。 我沒有找到以前的ASP.NET MVC .Net Framework中存在的函數IsAjaxRequest。 所以擴展方法的實現如下:

public static class HttpRequestExtensions
{
    private const string RequestedWithHeader = "X-Requested-With";
    private const string XmlHttpRequest = "XMLHttpRequest";

    public static bool IsAjaxRequest(this HttpRequest request)
    {
        if (request == null)
        {
            throw new ArgumentNullException("request");
        }

        if (request.Headers != null)
        {
            return request.Headers[RequestedWithHeader] == XmlHttpRequest;
        }

        return false;
    }
}

您可以在cshtml中使用這樣的...

@if (!this.Request.IsAjaxRequest())
{
    <div id="myCarousel" class="carousel slide" data-ride="carousel" data-interval="6000">
      <ol class="carousel-indicators">
        <li data-target="#myCarousel" data-slide-to="0" class="active"></li>
        <li data-target="#myCarousel" data-slide-to="1"></li>
        <li data-target="#myCarousel" data-slide-to="2"></li>
        <li data-target="#myCarousel" data-slide-to="3"></li>
      </ol>
    </div>
}

在模型方面,您需要一個模型列表,在我的例子中,Person ...

[BindProperty]
public List<Person> Persons { get; set; }

而ajax處理程序方法的帖子看起來像這樣

public void OnPostAjax()
{
    this.Persons.Add(new Person());
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM