Davood Kazemi
Davood Kazemi

Reputation: 105

Implementing a global search box in Layout. How to pass the search term as a query string?

I am really frustrated with this, Because I look so many questions and didn't find my answer. I want to implement a global search in my ASP Net Core project. But I want to implement a search box in Layout page, so that It could be used in every page.

My ASP Net Core project shows directors and movies' information. I built an independent razor page for showing the result of search. I used a property named SearchTerm to get the search term as a query string and then search it in database tables:

//from Search.cshtml.cs

[BindProperty(SupportsGet = true)]
public string SearchTerm { get; set; }

And I implemented a search box in Layout view:

@model MastersOfCinema.Pages.SearchModel
// (I referenced to "SearchModel" and with this I'm only able to open that page. Other pages give the error below.)

<header>
    <form method="get" class="SearchBox">
                        <div class="form-group">
                            <div class="input-group">
                                <input type="search" class="form-control" asp-for="SearchTerm" asp-route-searchTerm="SearchTerm" />
                                <span class="input-group-btn">
                                    <button class="btn btn-default" asp-page="./../Search">
                                        <i class="glyphicon glyphicon-search bg-light"></i>
                                    </button>
                                </span>
                            </div>
                        </div>
                    </form>
</header>

With the code above, I get this error when I open any page (except the search page which is referenced in layout):

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

The error is related to @model MastersOfCinema.Pages.SearchModel apparently. I don't know what to replace it. If I remove that, I get error from asp-for="SearchTerm". Because it doesn't recognise SearchTerm property.

Error CS1963 An expression tree may not contain a dynamic operation MastersOfCinema


I tried many approaches to implement a global search, including partial view and view components. But this is my first project and I am inexperienced. So please help me. Show me an easy approach.

Thanks for any help and if you need more information just ask.


The search works but as I said I get error when I open other pages. I can only open the seach page.

The search works but as I said I get error when I open other pages. I just can open the seach page.


In case you need to see the whole code of Search.cshtml.cs:

public class SearchModel : PageModel
    {
        private readonly Context _context;

        public SearchModel(Context context)
        {
            this._context = context;
        }

        public IEnumerable<Director> Director { get; set; }
        public IEnumerable<Movie> Movie { get; set; }
        [BindProperty(SupportsGet = true)]
        public string SearchTerm { get; set; }
        public async Task OnGetAsync(string searchTerm)
        {
            Director = await _context.Director.ToListAsync();
            Movie = await _context.Movie.ToListAsync();
            Director = GetDirectorByName(SearchTerm);
            Movie = GetMovie(SearchTerm);
            SearchTerm = searchTerm;

        }

        public IEnumerable<Director> GetDirectorByName(string searchString)
        {
            var query = from r in _context.Director
                        where r.Name.Contains(searchString) || r.Bio.Contains(searchString) ||
                        r.Country.Contains(searchString) || string.IsNullOrEmpty(searchString)
                        orderby r.Name
                        select r;

            if (query.Any()) { searchTermFound = true; }

            return query;
        }
        public IEnumerable<Movie> GetMovie(string searchString)
        {
            var query = from r in _context.Movie
                        where r.Title.Contains(searchString) || string.IsNullOrEmpty(searchString)
                        orderby r.Title
                        select r;

            if (query.Any()) { searchTermFound = true; }

            return query;
        }

        public bool searchTermFound = false;

    }

Upvotes: 2

Views: 2086

Answers (1)

Fei Han
Fei Han

Reputation: 27803

I want to implement a search box in Layout page, so that It could be used in every page

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

To fix the issue and achieve the requirement, you can try to remove @model MastersOfCinema.Pages.SearchModel from _Layout.cshtml, then manually set name and value attribute of input field, like below.

<form method="get" class="SearchBox">
    <div class="form-group">
        <div class="input-group">
            @*<input type="search" class="form-control" asp-for="SearchTerm" asp-route-searchTerm="SearchTerm" />*@
            <input type="search" class="form-control" name="SearchTerm" value="@ViewData["SearchTerm"]" asp-route-searchTerm="SearchTerm" />
            <span class="input-group-btn">
                <button class="btn btn-default" asp-page="./Search">
                    <i class="glyphicon glyphicon-search bg-light"></i>Search
                </button>
            </span>
        </div>
    </div>
</form>

In Search.cshtml.cs

public async Task OnGetAsync(string searchTerm)
{
    //...

    ViewData["SearchTerm"] = SearchTerm;

}

Test Result

enter image description here

Upvotes: 1

Related Questions