我正在构建一个应用程序,我的应用程序的一个要求是,当用户必须创建每个事务的卷时,用户希望能够在单击保存之前放置多个事务,因此用户可以选择添加到表的一行(使用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>
以下是我的两个问题:
很抱歉,我问了两个问题,但两者都与同一问题有关。
非常感谢你对此的帮助。
答案 0 :(得分:2)
MVC binder将使用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)) + " " + 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>
}
答案 1 :(得分:2)
我认为你应该尝试这样的事情
@{
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/
答案 2 :(得分:1)
如果您不想刷新页面,可以使用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响应仅限于表单内容,则无法将无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());
}