London Dev Meetup Rescheduled! Due to unavoidable reasons, the event has been moved to 21st May. Speakers remain the same—any changes will be communicated. Seats are limited—register here to secure your spot!
London Dev Meetup Rescheduled! Due to unavoidable reasons, the event has been moved to 21st May. Speakers remain the same—any changes will be communicated. Seats are limited—register here to secure your spot!
Hi,
I have created a Gist with the code I have written and using for paging (works for any IEnumerable<T>) that you can take a look at. You can find it here. To use this code you can modify your search page view model by changing the type of the Hits property to IPagedEnumerable<SearchHit>:
public IPagedEnumerable<SearchHit> Hits { get; set; }
Next, modify your action so it handles a page querystring parameter:
public ViewResult Index(SearchPage currentPage, string q, int page = 1)
And in your action where you create an instance of the view model you set the Hits property like this:
int pageSize = 10; var hits = Search(q.Trim(), ContentReference.StartPage, ControllerContext.HttpContext, currentPage.LanguageID).ToList(); model.Hits = new PagedList<SearchPageModel.SearchHit>(HttpContext, hits, page, pageSize) { QueryParamName = "page" };
Finally in the view, somewhere below or above the search results, you render the paging partial that you can find in the Gist:
@{ Html.RenderPartial("_Paging", Model.Hits); }
I would also modify the SearchService class in Alloy so it handles paging, so you only get back the results for the current page. In the implementation I have (maybe it's an old version of Alloy) it just gets the 40 first hits. This Search method should be changed from:
public virtual SearchResults Search(string searchText, PageReference rootPage, HttpContextBase context, string languageBranch, string[] fileDirectories, int maxResults) { var query = CreateQuery(searchText, rootPage, context, languageBranch, fileDirectories); return _searchHandler.GetSearchResults(query, 1, maxResults); }
To:
public virtual SearchResults Search(string searchText, PageReference rootPage, HttpContextBase context, string languageBranch, string[] fileDirectories, int page, int pageSize) { var query = CreateQuery(searchText, rootPage, context, languageBranch, fileDirectories); return _searchHandler.GetSearchResults(query, page, pageSize); }
Next you should modify the Search method in the SearchPage controller:
private IEnumerable<SearchPageModel.SearchHit> Search(string searchText, PageReference rootPage, HttpContextBase context, string languageBranch, int page, int pageSize, out int numberOfHits) { var searchResults = _searchService.Search(searchText, rootPage, context, languageBranch, _fileDirectories, page, pageSize); numberOfHits = searchResults.TotalHits; return searchResults.IndexResponseItems.SelectMany(CreateHitModel); }
And finally, use this code in the Index action:
int numberOfHits; int pageSize = 10; var hits = Search(q.Trim(), ContentReference.StartPage, ControllerContext.HttpContext, currentPage.LanguageID, page, pageSize, out numberOfHits).ToList(); model.Hits = new PagedList<SearchPageModel.SearchHit>(HttpContext, hits, numberOfHits, page, pageSize) { QueryParamName = "page" }; model.NumberOfHits = numberOfHits;
When modifying the Search Service I have a different version (IEnumerable<ContentReference> searchRoots instead of PageReference rootPage).
If I modifiy it I will also need to modify the CreateQuery method.
These are my versions.
Search
public virtual SearchResults Search(string searchText, IEnumerable<ContentReference> searchRoots, HttpContextBase context, string languageBranch, int maxResults) { var query = CreateQuery(searchText, searchRoots, context, languageBranch); return _searchHandler.GetSearchResults(query, 1, maxResults); }
CreateQuery
private IQueryExpression CreateQuery(string searchText, IEnumerable<ContentReference> searchRoots, HttpContextBase context, string languageBranch) { //Main query which groups other queries. Each query added //must match in order for a page or file to be returned. var query = new GroupQuery(LuceneOperator.AND); //Add free text query to the main query query.QueryExpressions.Add(new FieldQuery(searchText)); //Search for pages using the provided language var pageTypeQuery = new GroupQuery(LuceneOperator.AND); pageTypeQuery.QueryExpressions.Add(new ContentQuery<PageData>()); pageTypeQuery.QueryExpressions.Add(new FieldQuery(languageBranch, Field.Culture)); //Search for media without languages var contentTypeQuery = new GroupQuery(LuceneOperator.OR); contentTypeQuery.QueryExpressions.Add(new ContentQuery<MediaData>()); contentTypeQuery.QueryExpressions.Add(pageTypeQuery); query.QueryExpressions.Add(contentTypeQuery); //Create and add query which groups type conditions using OR var typeQueries = new GroupQuery(LuceneOperator.OR); query.QueryExpressions.Add(typeQueries); foreach (var root in searchRoots) { var contentRootQuery = new VirtualPathQuery(); contentRootQuery.AddContentNodes(root, _contentLoader); typeQueries.QueryExpressions.Add(contentRootQuery); } var accessRightsQuery = new AccessControlListQuery(); accessRightsQuery.AddAclForUser(PrincipalInfo.Current, context); query.QueryExpressions.Add(accessRightsQuery); return query; }
It also says that _fileDirectories doesn't exist in the SearchPageController.
Hi everyone!
I'm trying to sort the search results of the Alloy example MVC in pages but I don't know how to start doing it and I need someone who guides me a little bit in my way to do it.
I'm not using EPiServer Find, is essential to use it to make this work?
Thanks =)