skip to Main Content

I understand that the SelectListItems are meant to not return back the items on post and perhaps be null, but because of this my ModelState.IsValid condition is always false and the Studies field which contains the list is the one with the invalid attribute. I tried different methods and am stuck on resolving this

View

 <label asp-for="Studies" class="form-label"></label>
 <select asp-for="SelectedStudyGuid" asp-items="@Model.Studies" class="form-control" autocomplete="off">
   <option value="">Select Study</option>
 </select>
 <span asp-validation-for="SelectedStudyGuid" class="text-danger"></span>

ViewModel

public class AddStudyViewModel
{
    public string ParticipantGuid { get; set; }

    public IEnumerable<SelectListItem> Studies { get; set; }
    public string SelectedStudyGuid { get; set; }
    
    [DataType(DataType.Date)]
    public DateTime? StartDate { get; set; }
    
    [DataType(DataType.Date)]
    public DateTime? EndDate { get; set; }
}

Controller

  private List<SelectListItem> GetStudyCatalog()
    {
        return _repo.GetStudyCatalog().Select(s => new SelectListItem
        {
            Text = s.Name,
            Value = s.Guid
        }).ToList();
    }

    [HttpGet]
    public IActionResult AddStudy(string participantGuid)
    {
        var model = new AddStudyViewModel
        {
            Studies = GetStudyCatalog(),
            ParticipantGuid = participantGuid
        };
        
        return PartialView("_AddStudyModal", model);
    }

    [HttpPost]
    public IActionResult AddStudy(AddStudyViewModel model)
    {
        if (ModelState.IsValid)
        {
           var response= _repo.AddStudy(model.SelectedStudyGuid, model.ParticipantGuid, model.StartDate, model.EndDate);
           
            if (response.Success)
            {
                TempData["Message"] = response.Message;
                return RedirectToAction("EditParticipant", new {id = response.NewGuid});
            }
        }

        model.Studies = GetStudyCatalog();
        return PartialView("_AddStudyModal", model);
    }

2

Answers


  1. The problem is originated when you click your button to submit the form data back to the controller.

    At this point the client side code sends the input fields present on the form and you don’t have an input field that contains the SelectListItem. The SelectedStudyGuid select list is for that field, not for the whole Studies.

    The AddStudyViewModel instance received in the post action is rebuilt on the server side using the data sent by the client side and thus you have a null for the Studies property.

    Usually the SelectListItem data is not needed on the post action but only in the get action and you can simply pass it using some temporary storage like the ViewBag

    So you can fix with

    MODEL

    public class AddStudyViewModel
    {
        public string ParticipantGuid { get; set; }
    
        public string SelectedStudyGuid { get; set; }
        
        [DataType(DataType.Date)]
        public DateTime? StartDate { get; set; }
        
        [DataType(DataType.Date)]
        public DateTime? EndDate { get; set; }
    }
    

    CONTROLLER

    [HttpGet]
    public IActionResult AddStudy(string participantGuid)
    {
        var model = new AddStudyViewModel
        {
            ParticipantGuid = participantGuid
        };
        ViewBag.Studies = GetStudyCatalog(),
        return PartialView("_AddStudyModal", model);
    }
    

    VIEW

     <label asp-for="Studies" class="form-label"></label>
     <select asp-for="SelectedStudyGuid" asp-items="@ViewBag.Studies" class="form-control" autocomplete="off">
       <option value="">Select Study</option>
     </select>
     <span asp-validation-for="SelectedStudyGuid" class="text-danger"></span>
    
    Login or Signup to reply.
  2. This can happen only if you use net 6. To fix it simply make Studies nullable

    public List<SelectListItem>? Studies { get; set; }
    

    or what is the smart developers do , they just remove nullables from the projests

     <TargetFramework>net6.0</TargetFramework>
        <!--<Nullable>enable</Nullable>-->
    

    to use a ViewBag instead of a ViewModel is very unprofessional

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search