locked
How to add search form in _Layout Razor Pages? RRS feed

  • Question

  • User-833093536 posted

    My search code look like this:

            <form class="col row mr-auto" asp-page="./Index" method="get">
                <div class="form-inline my-2 my-lg-0 ml-auto">
                        <input class="form-control mr-sm-2" type="search"
                               placeholder="Search" aria-label="Search" name="SearchString" value="@Model.CurrentFilter" />
                        <input type="submit" value="Search" class="btn btn-outline-success my-2 my-sm-0" />
                </div>
            </form>
    

    I created a web design with search navigation bar which is located in Layout File. How can i add search form in Layout file? I Found an answer with Html.BeginForm method, which requires Action and Controller name. But my web app is built on Razor Pages.

    Sunday, November 10, 2019 12:13 PM

Answers

  • User711641945 posted

    Hi mejanh,

    You could  create a BaseModel class that has an CurrentFilter property. All of your other PageModels would inherit form that instead of PageModel, and you can add @model BaseModel to the Layout page so that your input tag helper works:

    public class BaseModel:PageModel
    {
        public string CurrentFilter { get; set; }
    }

    _Layout.cshtml:

    @model BaseModel
    <div class="container">
        <partial name="_CookieConsentPartial" />
        <main role="main" class="pb-3">
            <form class="col row mr-auto" asp-page="./Index" method="get">
                <div class="form-inline my-2 my-lg-0 ml-auto">
                    <input class="form-control mr-sm-2" type="search"
                            placeholder="Search" aria-label="Search" name="SearchString" value="@Model.CurrentFilter" />
                    <input type="submit" value="Search" class="btn btn-outline-success my-2 my-sm-0" />
                </div>
            </form>
            @RenderBody()
        </main>
    </div>

    Notes:`asp-page="./Index"` means that your Index.cshtml should be in `Pages` main folder.If your razor pages is in folder like `Pages/Tests/Index.cshtml`,it should be `asp-page="Tests/Index"`.

    Here is a simple demo like below:

    1.Model:

    public class Tests
    {
        public int Id { get; set; }
        public string FullName { get; set; }
    }

    2.Index.cshtml:

    @page
    @model IndexModel
    @{
        ViewData["Title"] = "Home page";
    }
    
    <table class="table">
        <thead>
            <tr>
                <th>
                    @Html.DisplayNameFor(model => model.Test[0].Id)
                </th>
                <th>
                    @Html.DisplayNameFor(model => model.Test[0].FullName)
                </th>          
                <th></th>
            </tr>
        </thead>
        <tbody>
            @foreach (var item in Model.Test)
            {
                <tr>
                    <td>
                        @Html.DisplayFor(modelItem => item.Id)
                    </td>
                    <td>
                        @Html.DisplayFor(modelItem => item.FullName)
                    </td>               
                </tr>
            }
        </tbody>
    </table>

    3.Index.cshtml.cs:

    public class IndexModel : BaseModel
    {
        private readonly RazorForumContext _context;
    
        public IndexModel(RazorForumContext context)
        {
            _context = context;
        }
        public IList<Test> Test { get; set; }
    
        public async Task OnGet(string searchString)
        {
            var tests= from p in _context.Tests
                            select p;
            CurrentFilter = searchString;
            if (!string.IsNullOrEmpty(searchString))
            {
                tests= tests.Where(s => s.FullName.Contains(searchString));
            }
            Test = await tests.ToListAsync();
        }
    }

    Best Regards,

    Rena

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Monday, November 11, 2019 2:16 AM

All replies

  • User-821857111 posted

    What is Model.CurrentFilter?

    Sunday, November 10, 2019 6:22 PM
  • User-474980206 posted

    if you need a default value for the layout, you have a couple options. add the value to all view models with an interface, or use viewbag and either middleware or base page class.

     

    Sunday, November 10, 2019 9:05 PM
  • User711641945 posted

    Hi mejanh,

    You could  create a BaseModel class that has an CurrentFilter property. All of your other PageModels would inherit form that instead of PageModel, and you can add @model BaseModel to the Layout page so that your input tag helper works:

    public class BaseModel:PageModel
    {
        public string CurrentFilter { get; set; }
    }

    _Layout.cshtml:

    @model BaseModel
    <div class="container">
        <partial name="_CookieConsentPartial" />
        <main role="main" class="pb-3">
            <form class="col row mr-auto" asp-page="./Index" method="get">
                <div class="form-inline my-2 my-lg-0 ml-auto">
                    <input class="form-control mr-sm-2" type="search"
                            placeholder="Search" aria-label="Search" name="SearchString" value="@Model.CurrentFilter" />
                    <input type="submit" value="Search" class="btn btn-outline-success my-2 my-sm-0" />
                </div>
            </form>
            @RenderBody()
        </main>
    </div>

    Notes:`asp-page="./Index"` means that your Index.cshtml should be in `Pages` main folder.If your razor pages is in folder like `Pages/Tests/Index.cshtml`,it should be `asp-page="Tests/Index"`.

    Here is a simple demo like below:

    1.Model:

    public class Tests
    {
        public int Id { get; set; }
        public string FullName { get; set; }
    }

    2.Index.cshtml:

    @page
    @model IndexModel
    @{
        ViewData["Title"] = "Home page";
    }
    
    <table class="table">
        <thead>
            <tr>
                <th>
                    @Html.DisplayNameFor(model => model.Test[0].Id)
                </th>
                <th>
                    @Html.DisplayNameFor(model => model.Test[0].FullName)
                </th>          
                <th></th>
            </tr>
        </thead>
        <tbody>
            @foreach (var item in Model.Test)
            {
                <tr>
                    <td>
                        @Html.DisplayFor(modelItem => item.Id)
                    </td>
                    <td>
                        @Html.DisplayFor(modelItem => item.FullName)
                    </td>               
                </tr>
            }
        </tbody>
    </table>

    3.Index.cshtml.cs:

    public class IndexModel : BaseModel
    {
        private readonly RazorForumContext _context;
    
        public IndexModel(RazorForumContext context)
        {
            _context = context;
        }
        public IList<Test> Test { get; set; }
    
        public async Task OnGet(string searchString)
        {
            var tests= from p in _context.Tests
                            select p;
            CurrentFilter = searchString;
            if (!string.IsNullOrEmpty(searchString))
            {
                tests= tests.Where(s => s.FullName.Contains(searchString));
            }
            Test = await tests.ToListAsync();
        }
    }

    Best Regards,

    Rena

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Monday, November 11, 2019 2:16 AM
  • User-833093536 posted

    I followed the .net documentation(https://docs.microsoft.com/en-us/aspnet/core/data/ef-rp/sort-filter-page?view=aspnetcore-3.0) for creating search form. that is where currentfilter came from.

    Monday, November 11, 2019 5:16 AM
  • User-833093536 posted

    So, Basically you are asking to call the PageModel in the layout file too? even though i added the PageModel in Razor page. isn't going to consume more memory using same model twice?

    This is how i solved the problem for now:

    _Layout File =>

                            <form asp-page="/Home/Search" class="nav-item" method="get">
                                <input type="text" placeholder="Search..." name="SearchString" class="search nav-link">
                                <input type="submit" hidden>
                            </form>
    

    I added search form in a razor page and redirect it form the layout file by asp-page tag helper. but i didn't wanted to show the search form in the razor page. so i added the Html "hidden" method in search form to get rid of it. What i was unable to do is, i could not show the search value in search form navigation. that is why i asked the question.

    I created Razor Page Filter by following the .net documentation(https://docs.microsoft.com/en-us/aspnet/core/data/ef-rp/sort-filter-page?view=aspnetcore-3.0).

    My Razor Page From =>

            <form asp-page="/Home/Search" method="get" hidden>
                <input type="search"
                       placeholder="Search" aria-label="Search" class="src-box-input" name="SearchString" value="@Model.CurrentFilter" />
                <button type="submit" class="src-link-button"><i class="fas fa-search"></i></button>
            </form>
    

    Thank You, Rena for helping. Looks like it is the only way.

    Monday, November 11, 2019 5:36 AM