Reputation: 11
ok so i am trying to create a some generic components but i am having some issues passing the AspFor value in the .cshtml
i created an input model and the partial
public class InputModel : ComponentModel
{
public string AspFor { get; set; }
public string Value { get; set; }
public string? Disabled { get; set; }
}
public class ComponentModel
{
public string Id { get; set; }
public string Label { get; set; }
public bool IsMandatory { get; set; }
public ComponentEnum Componente { get; set; }
}
public enum ComponentEnum
{
Input
}
public static class ComponentEnumExtensions
{
public static string GetPath(this ComponentEnum component)
{
return component switch
{
ComponentEnum.Input => "*Path_To_Input.cshtml*"
_ => string.Empty
};
}
}
<div id="@Model.Id-container" class="form-select-container">
<label class="text-blue800 steps-subtitle">@(Model.Label)</label>
@if (Model.IsMandatory)
{
<span class="text-primary">(Mandatory)</span>
}
<label asp-for="@Model.AspFor" class="form-label">@Model.Label</label>
<input asp-for="@Model.AspFor" class="form-control" value="@Model.Value" />
</div>
i am then creating an instance of the input model and rendering it in the page with this model:
public class RegistoViewModel
{
public Contactos Contactos { get; set; }
}
public class Contactos
{
[Required(ErrorMessage = "Email is required")]
[EmailAddress(ErrorMessage = "Invalid email address")]
public string Email { get; set; } = string.Empty;
}
@{
var input = new InputModel
{
Id = "inputId",
Label = "Email",
Componente = ComponentEnum.Input,
AspFor = "Contactos.Email",
Value = Model.Contactos.Email
};
}
@await Html.PartialAsync(ComponentEnum.Input.GetPath(), input)
can someone help me understand how can i pass the AspFor dynamicaly and be able to create a generic InputModel
when i create the Div directly in the page it works ok:
<div class="mt-4">
<div id="@Model.Test.Id-container" class="form-select-container">
<label class="text-blue800 steps-subtitle">@(Model.Test.Label)</label>
@if (Model.Test.IsMandatory)
{
<span class="text-primary">(Obrigatório)</span>
}
<label asp-for="Contactos.Email" class="form-label">Email</label>
<input asp-for="Contactos.Email" class="form-control" value="@Model.Test.Value" />
</div>
</div>
public class RegistoViewModel
{
public Contactos Contactos { get; set; }
public InputModel Test{ get; set; }
}
public class Contactos
{
[Required(ErrorMessage = "Email is required")]
[EmailAddress(ErrorMessage = "Invalid email address")]
public string Email { get; set; } = string.Empty;
}
Upvotes: 1
Views: 52
Reputation: 9054
You could try create a custom render helper which accept string modelname and propertyname:
public static class HtmlHelpers
{
public static IHtmlContent CustomInputFor(
this IHtmlHelper htmlHelper,
string modelTypeName,
string propertyName,
object? value = null,
object? htmlAttributes = null)
{
// Get the Type from the model type name
Type? modelType = Type.GetType(modelTypeName);
if (modelType == null)
{
throw new ArgumentException($"Model type '{modelTypeName}' not found.");
}
// If no value is provided, try to create an instance and get the default property value
if (value == null)
{
object? modelInstance = Activator.CreateInstance(modelType);
if (modelInstance != null)
{
PropertyInfo? property = modelType.GetProperty(propertyName);
if (property != null)
{
value = property.GetValue(modelInstance);
}
}
}
// Convert attributes to HTML attributes
var attributes = HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes);
// Generate the HTML input
TagBuilder inputTag = new("input");
inputTag.MergeAttribute("name", propertyName);
inputTag.MergeAttribute("value", value?.ToString());
inputTag.MergeAttributes(attributes, replaceExisting: true);
// Render the input
using var writer = new System.IO.StringWriter();
inputTag.WriteTo(writer, System.Text.Encodings.Web.HtmlEncoder.Default);
return new HtmlString(writer.ToString());
}
}
Then use the helper in parital view like
<div id="@Model.Id-container" class="form-select-container">
<label class="text-blue800 steps-subtitle">@Model.Label</label>
@if (Model.IsMandatory)
{
<span class="text-primary">(Mandatory)</span>
}
@Html.CustomInputFor("ProjectName.Models.Contactos", "Email","[email protected]", new { @class = "form-control" })
</div>
Just note that Type.GetType(modelTypeName);
requires format like "namespace.Contactos"
Upvotes: 0