Search code examples
asp.net-corerazorrazor-pages

How to dynamically insert strings from code-behind into the asp-for properties of Razor Pages elements


Can I somehow take string values from a class and insert those string values into the values of the asp-for property of a Razor Page HTML element?

I have a class like below that just contains the names of the Days of the Week:

public class Days
{
    [BindProperty]
    public static List<string> DaysList { get; set; } = new List<string>
    {
        new string("Saturday"),
        new string("Sunday"),
        new string("Monday"),
        new string("Tuesday"),
        new string("Wednesday"),
        new string("Thursday"),
        new string("Friday")
    };
}  

I want to be able to dynamically use the names of the week to build out asp-for values that are actual var/property names. Like in asp-for="@(Day)StartTime", it would actually be a variable in the code behind named SaturdayStartTime, SundayStartTime, etc. Then for @SpanHours the same would apply there as a property of MyObject which is MyObject.SaturdaySpanHours, MyObject.SundaySpanHours, etc.

I was just hoping to be able to implement it via foreach like below, but that doesn't work.

<div>
    @{ 
        foreach (string Day in Days.DaysList)
        {
            string SpanHours = "MyObject." + Day + "SpanHours";
            
            <input type="time" value="@Model.MyObject.@(Day)StartTime.ToString("HH:mm")" asp-for="@(Day)StartTime" />
            <input asp-for="@SpanHours" class="form-control" value=@Model.MyObject.@(Day)SpanHours />
            
        }
    }
</div>

Is there another method to be able to dynamically insert values into the asp-for properties?


Solution

  • Don't use the asp-for attribute to bind the frontend to the backend; use the name property instead:

    <input name="@SpanHours" id="@SpanHours" class="form-control" value=@Model.MyObject.@(Day)SpanHours />
    

    You'll need id as well for targeting the element via any frontend (JavaScript) processing.


    The documentation page on Model Binding has a section on the various Sources for picking up binding:

    By default, model binding gets data in the form of key-value pairs from the following sources in an HTTP request:

    • Form fields
    • The request body (For controllers that have the [ApiController] attribute.)
    • Route data
    • Query string parameters
    • Uploaded files

    For each target parameter or property, the sources are scanned in the order indicated in the preceding list. There are a few exceptions:

    • Route data and query string values are used only for simple types.
    • Uploaded files are bound only to target types that implement IFormFile or IEnumerable.

    If the default source is not correct, use one of the following attributes to specify the source:

    • [FromQuery] - Gets values from the query string.
    • [FromRoute] - Gets values from route data.
    • [FromForm] - Gets values from posted form fields.
    • [FromBody] - Gets values from the request body.
    • [FromHeader] - Gets values from HTTP headers.

    And if you click on any of those attribute links on that page, you'll see they all have two properties. E.g., for forms:

    Property Description
    Binding Source Gets the BindingSource.
    Name The form field name.

    The relevant front-end property here being Name.