Home > Back-end >  Populate Dropdown List from Layout Page encountering error when navigating to other page
Populate Dropdown List from Layout Page encountering error when navigating to other page

Time:10-14

Using .NET Core 3.1 with Razor Page Handler, I want to be able to populate a dropdown list from the layout page.

_layout.cshtml

@model IndexModel
<nav>
<ul>
    <li >
          <a  href="#" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">@Localizer["Students"]</a>
          <div  aria-labelledby="navbarDropdown">
          <a  asp-area="@Areas.Admins" asp-page="ListStudents">@Localizer["ListStudents"]</a>
       </div>
    </li>
    <li >
         <select asp-items="@Model.ClassList" onchange="refreshPage(this)" >
              @if (Model.ClassList.Count > 1){
                     <option value="All">@Localizer["SelectClass"]</option>
              }
          </select>
    </li>
</ul>
</nav>
@RenderBody()

the dropdown works on page load, but when I navigate to another page like ListStudents

I encountering an error

InvalidOperationException: The model item passed into the ViewDataDictionary is of type '..Pages.ListStudentsModel', but this ViewDataDictionary instance requires a model item of type '..Pages.IndexModel'.

Index.cshtml.cs

public class IndexModel : PageModel
{
    private readonly IClassService _classService;
    public List<SelectListItem> ClassList { get; set; }

    public IndexModel(IClassService classService)
    {
        _classService = classService;
        ClassList = new List<SelectListItem>();
    }

    public async Task OnGet()
    {
        ClassList = await _classService.GetClassList();
    }
}

ListStudents.cshtml.cs

public class ListStudentsModel : PageModel
{
    public ListStudentsModel()
    {
    }

    public async Task<IActionResult> OnGetAsync()
    {
        // some code here
        return Page();
    }
}

I'm not sure if this is the right idea or if should I use a partial view or component (I'm struggling with this part)

I tried to replace the dropdown with a another partial page

@await Html.PartialAsync("/Pages/ClassDropdown.cshtml", new ClassDropdownModel())

ClassDropdown.cshtml

@page
@model ClassDropdownModel
<span>Test</span>

ClassDropdown.cshtml.cs

public class ClassDropdownModel: PageModel
    {
        private readonly IClassService _classService;
        public List<SelectListItem> ClassList { get; set; }
    
        public IndexModel(IClassService classService)
        {
            _classService = classService;
            ClassList = new List<SelectListItem>();
        }

        public async Task OnGet()
        {
            ClassList = await _classService.GetClassList();
        }
    }

but I'm getting error on "new ClassDropdownModel()" saying there's no argument given that corresponds to the required formal parameter 'classService'

CodePudding user response:

It seems that it's only possible with View Component and very easy to implement

Removed @model IndexModel from _layout

then added the ff:

ViewComponents/ClassesViewComponent.cs

[ViewComponent(Name = "Classes")] 
    public class ClassesViewComponent : ViewComponent
    {
        private readonly IClassService _classService;
        public ClassesViewComponent(IClassService classService)
        {
            _classService = classService;
        }

        public async Task<IViewComponentResult> InvokeAsync()
        {
            var classList = await _classService.GetClassList();
            return View("Classes", classList );
        }
    }

Pages/Shared/Components/Classes/Classes.chtml

@inject IHtmlLocalizer<SharedResource> Localizer
@model List<KeyValuePair<string,string>>

<select onchange="refreshPage(this)" >
    @if (Model.Count() > 1){
        <option value="All">@Localizer["SelectClasses"]</option>
}                                  
@foreach (var class in Model){
        <option value="@class.Value">@class.Key</option>
}
</select>

_layout

@await Component.InvokeAsync("Classes")
  • Related