I want to write a Edit.cshtml file for an entity with many properties to edit, so I have to write the following codes many times:
<div class="form-group">
<label asp-for="Email" class="col-md-2 control-label"></label>
<div class="col-md-10">
<input asp-for="Email" class="form-control" />
<span asp-validation-for="Email" class="text-danger"></span>
</div>
</div>
Actually, there are many entities so that I have to write many Edit.cshtml files. I want to make some simplifications
I want to select some properties of the entity in the controller and use loop to show the properties in the view. For example: In the controller file:
public IActionResult Edit(string id)
{
var model = GetModel(id);
var propertyNames= new List<string>()
{
"Name",
"Email"
// add some other property names of the entity
};
ViewData["PropertyList"] = propertyNames;
return View(model);
}
In the view file:
@{
var propertyNames = (List<string>)ViewData["PropertyList"];
foreach (string item in propertyNames)
{
<div class="form-group">
<label asp-for="@(item)" class="col-md-2 control-label"></label>
<div class="col-md-3">
<input asp-for="@(item)" class="form-control" />
<span asp-validation-for="@(item)" class="text-danger"></span>
</div>
</div>
}
}
but it cannot work, since it generates wrong codes. It seems that I cannot pass a string value for "asp-for" tag helper.
For example, if I change the code of top to this:
@{
string e = "Email";
<div class="form-group">
<label asp-for="@e" class="col-md-2 control-label"></label>
<div class="col-md-10">
<input asp-for="@e" class="form-control" />
<span asp-validation-for="@e" class="text-danger"></span>
</div>
</div>
}
The code above will generate this:
<div class="form-group">
<label class="col-md-2 control-label" for="e">e</label>
<div class="col-md-10">
<input class="form-control" type="text" id="e" name="e" value="Email" />
<span class="text-danger field-validation-valid" data-valmsg-for="e" data-valmsg-replace="true"></span>
</div>
</div>
The expected code is:
<div class="form-group">
<label class="col-md-2 control-label" for="Email">Email</label>
<div class="col-md-10">
<input class="form-control" type="email" data-val="true" data-val-email="Email 字段不是有效的电子邮件地址。" data-val-required="Email 字段是必需的。" id="Email" name="Email" value="" />
<span class="text-danger field-validation-valid" data-valmsg-for="Email" data-valmsg-replace="true"></span>
</div>
</div>
How should I do?
Is it possible in razor?
When we need to pass content between the HTML pages or aspx Web Forms in the context of ASP.NET, a Query String is very easy to use and the Query String follows a separating character, usually a Question Mark (?). It is basically used for identifying data appearing after this separating symbol.
To use a query string to pass information In the source page when you specify the URL of the target page, include the information that you want to pass in the form of key-value pairs at the end of the URL. The first pair is preceded by a question mark (?) and subsequent pairs are preceded by ampersands(&), as shown in the following example:
The HTTP query string is specified by the values following the question mark (?). As you can see from the above query string example (just after “?”), we are passing the parameters in key:value pair, meaning that id is a key variable and txtId.Text is a value of that key.
If you are using Vb.net as code-behind, then use the following code: To get the query string values to another page, we need to use the following code to the page that we mentioned in query string url. I used Page2.aspx as example. Add the following code snippet to your code-behind file of Page2.aspx as below.
Ok, I managed to get this working. DISCLAIMER: It is super hacky and I have no idea if I've done it in the best way possible. All I know is that it does what you want and it might point you in the right direction.
Firstly, I created a model:
using System.ComponentModel.DataAnnotations;
namespace WebApplication1.Models
{
public class TestModel
{
[Required]
public string Name { get; set; }
[Required]
[EmailAddress]
[Display(Name = "Email Address")]
public string Email { get; set; }
}
}
Then, I made a custom tag helper. This is the horrible bit where the "magic" happens. Specifically the first section of the Process
method...
using Microsoft.AspNet.Mvc.Rendering;
using Microsoft.AspNet.Mvc.ViewFeatures;
using Microsoft.AspNet.Razor.TagHelpers;
using System.Linq;
namespace WebApplication1.TagHelpers
{
[HtmlTargetElement("edit")]
public class EditTagHelper : TagHelper
{
[HtmlAttributeName("asp-for")]
public ModelExpression aspFor { get; set; }
[ViewContext]
[HtmlAttributeNotBound]
public ViewContext ViewContext { get; set; }
protected IHtmlGenerator _generator { get; set; }
public EditTagHelper(IHtmlGenerator generator)
{
_generator = generator;
}
public override void Process(TagHelperContext context, TagHelperOutput output)
{
var propName = aspFor.ModelExplorer.Model.ToString();
var modelExProp = aspFor.ModelExplorer.Container.Properties.Single(x => x.Metadata.PropertyName.Equals(propName));
var propValue = modelExProp.Model;
var propEditFormatString = modelExProp.Metadata.EditFormatString;
var label = _generator.GenerateLabel(ViewContext, aspFor.ModelExplorer,
propName, propName, new { @class = "col-md-2 control-label", @type = "email" });
var input = _generator.GenerateTextBox(ViewContext, aspFor.ModelExplorer,
propName, propValue, propEditFormatString, new { @class = "form-control" });
var validation = _generator.GenerateValidationMessage(ViewContext, aspFor.ModelExplorer,
propName, string.Empty, string.Empty, new { @class = "text-danger" });
var inputParent = new TagBuilder("div");
inputParent.AddCssClass("col-md-10");
inputParent.InnerHtml.Append(input);
inputParent.InnerHtml.Append(validation);
var parent = new TagBuilder("div");
parent.AddCssClass("form-group");
parent.InnerHtml.Append(label);
parent.InnerHtml.Append(inputParent);
output.Content.SetContent(parent);
base.Process(context, output);
}
}
}
NB: To make the custom TagHelper work, you need to add a line into the _ViewImports.cshtml
file, like this (replace WebApplication1
with your namespace):
@addTagHelper "*, WebApplication1"
I changed my action to this, to sort of match yours (maybe you can use reflection to get your model property names here?):
public IActionResult Index()
{
var propertyNames = new List<string>()
{
"Name",
"Email"
};
ViewData["PropertyList"] = propertyNames;
var m = new TestModel()
{
Name = "huoshan12345",
Email = "[email protected]"
};
return View(m);
}
Then finally, in the view, you can do something like this:
<div class="row">
@using (Html.BeginForm())
{
var propertyNames = (List<string>)ViewData["PropertyList"];
foreach (string item in propertyNames)
{
<edit asp-for="@item"></edit>
}
<input type="submit" value="Submit" />
}
</div>
You can also try this:
foreach (string item in propertyNames){
@Html.TextBox(item, value: null, htmlAttributes: new { @class = "form-control" })
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With