Search code examples
c#asp.net-mvcasp.net-coremodel-binding

ASP.NET MVC : binding to model within a loop


I'm pretty new to ASP.NET MVC, and I'm trying to figure out if I am able to bind data to my model property from within a loop.

Can I bind it maybe in the onClick event?

At the moment chosenTime is 1/01/0001 12:00:00 AM.

My code for the view is as follows:

@model ResSProject.Models.Sittings.SittingTimesVM

<div class="d-flex justify-content-center">

    <div>@Model.RestaurantName</div>
    <div class="px-5">@Model.Date.ToString("dd-MMMM-yyyy")</div>
    <div>@Model.NumberOfGuests</div>
</div>
<form method="post" asp-action="Reservation">
    @{TimeSpan T1 = new TimeSpan(0, 15, 0);
     
        for (var increase = Model.SittingsStart.Subtract(T1); increase < Model.SittingsEnd;)
        {
            increase = increase.AddMinutes(15);

            <input class="btn btn-primary w-50 mx-auto mt-3 " type="button"  asp-for="ChosenTime" value="@increase.ToString("HH:mm tt")" />
        }
    }

    <input type="submit" value="Submit" />

    <input type="hidden" asp-for=NumberOfGuests />
    <input type="hidden" asp-for=Date />
    <input type="hidden" asp-for=RestaurantName />
    <input type="hidden" asp-for=RestaurantId />
    <input type="hidden" asp-for=SittingsStart />
    <input type="hidden" asp-for=SittingsEnd />
</form>

My view model class is:

using ResSProject.Data;
using System.ComponentModel.DataAnnotations;

namespace ResSProject.Models.Sittings
{
    public class SittingTimesVM
    {
        public DateTime Date { get; set; }
        public int RestaurantId { get; set; }
        public string RestaurantName { get; set; }
        public int NumberOfGuests { get; set; } 
        public DateTime ChosenTime { get; set; }
        public DateTime SittingsStart { get; set; }
        public DateTime SittingsEnd { get; set; }
    }
}

Solution

  • Button type element cannot be passed to backend. I think you need set a hidden input and use js to set the chosen time.

    Besides, the value of the inputs are just time without date(value="@increase.ToString("HH:mm tt")"). When you post the value, it will bind time with current date to the property ChosenTime. If the SittingsStart and SittingsEnd are not the same date with current now, the chosen time will be not correct.

    Whole working demo:

    @model SittingTimesVM
    
    <div class="d-flex justify-content-center">
    
        <div>@Model.RestaurantName</div>
        <div class="px-5">@Model.Date.ToString("dd-MMMM-yyyy")</div>
        <div>@Model.NumberOfGuests</div>
    </div>
    <form method="post" asp-action="Reservation">
        @{TimeSpan T1 = new TimeSpan(0, 15, 0);
         
            for (var increase = Model.SittingsStart.Subtract(T1); increase < Model.SittingsEnd;)
            {
                increase = increase.AddMinutes(15);
    
                <input class="btn btn-primary w-50 mx-auto mt-3 " type="button" asp-for="ChosenTime"
                     onclick="GetValue(this)"  value="@increase.ToString("dd-MMMM-yyy HH:mm tt")" />
                                           
            }
        }
        <input asp-for="ChosenTime" type="hidden"/>
        <input type="submit" value="Submit" />
    
        <input type="hidden" asp-for=NumberOfGuests />
        <input type="hidden" asp-for=Date />
        <input type="hidden" asp-for=RestaurantName />
        <input type="hidden" asp-for=RestaurantId />
        <input type="hidden" asp-for=SittingsStart />
        <input type="hidden" asp-for=SittingsEnd />
    </form>
    @section Scripts
    {
        <script>
            function GetValue(e)
            {    
                $('input:hidden[name=ChosenTime]').val($(e).val())
            }
        </script>
    }
    

    Backend:

    [HttpPost]
    public void Reservation(SittingTimesVM model)
    {
       //do your stuff...
    }
    

    Another way I better suggest is to combine <input> elements to one <select> element, and it is no need add any onclick event to set value. It can bind to model property successfully upon you set asp-for="ChosenTime" for the <select> element.

    @{
        TimeSpan T1 = new TimeSpan(0, 15, 0);
        <select  type="button" asp-for="ChosenTime">
            @for (var increase = Model.SittingsStart.Subtract(T1); increase < Model.SittingsEnd;)
            {
                increase = increase.AddMinutes(15);
                <option value="@increase.ToString("dd-MMMM-yyy HH:mm tt")">@increase.ToString("HH:mm tt")</option>                                       
            }
        </select>        
    }