SharePoint Search move to another page with same Query and Filters

NOTE: this is classic SP, meaning 2013, or classic experience in 365, classic sites, or in my case, Publishing Site Collection, even on O365 - SP Online.

 Scenario: I have a search page, for our randomly designed search results, with filters and paging, so far so good, SP provides everything except the design, for that we play with our design templates.

Now our darling customer asks us to make a dynamic page for our singe item result. 

Usually either we build a page-based system, and the results are pages, or even with documents-based system, usually we click on the docs and open them.

In our case we had documents, in a  Documents Library (where else?), with some columns, and when we click on a result we go to a customized page that projects the metadata (columns) to that page.

Again, so if we get a result for a PDF or Image, we now open another .aspx page, there we show the Title and Thumbnail and Description and so on of the file, most of them just more fields in the Documents Library.


So what were our challenges?

1. Provide image url to the image itself, when under Documents Library

2. Provide thumbnails to documents

3. When moving to single item page, collect our query, including fixing the selected item index

4. When in the single item page, run the query on our search results web part

5. Taming an reusing the hover panel with the preview of the files


1. Provide image url to the image itself, when under Documents Library

Eventually we found the the search results, although Path is always "/DispForm.aspx?ID=68" ect., there is another MMD named "DefaultEncodingURL" that returns the actual file path.


2. Provide thumbnails to documents

We initially tried the "getpreview.ashx" endpoint, but with long PDFs he just gave them fixed around 400px height, and therefor the width was les than 100px, and it looked terrible. I'll still write down the syntax for anyone using any 2013+ on-premise SP.

_spPageContextInfo.siteAbsoluteUrl + '/_layouts/15/getpreview.ashx?path=' + ctx.CurrentItem.Path

But witO365 we have our great Graph Engine that can also help us with Thumbnails, with high quality 

  img = location.origin + 

              '/_api/v2.0/sharePoint:' + 

              (ctx.CurrentItem.Path.replace(location.origin, '')) + 

              ':/driveItem/thumbnails/0/large/content?preferNoRedirect=true';



3. When moving to single item page, collect our query, including fixing the selected item index

When you are paging some search results there are 2 options. If you didn't filtered anything yet its really simple, the webparts just add some hash to your url like this "#k=#s=15#l=1033" where 'k' is part of the query text, 's' is the index to start with (s for start I guess), and 'l' should be for language support.

So if this is the case, let say I defined 6 results per page, moved 4 pages, so 's' is 24, and now I click on the 4th item, when moving to a simple item per page, I actually need to replace the value of 's' to 28. Some spitting and rebuilding does the trick (coming right up).

BUT if we have filters then there is a big object being built in your url hash zone, and it has the 's' hidden inside.

That obj is actually a JSON obj, containing 'k' as a string, 's' as an int, and 'r' for refiners, as an array.

I made a function to target all cases

function calcItemPageHref(idx){
  if (location.hash.includes('#Default=')){
    let x = JSON.parse(decodeURIComponent(location.hash).replace("#Default=",""))
    x.s += idx;
    location.hash = '#Default='+encodeURIComponent(JSON.stringify(x))
  } else if (location.hash.includes('#s=')){
    let index = location.hash.split("#s=")[1].split("#")[0]
    let rep = '#s=' + index
    index = parseInt(index) + idx
    location.hash = location.hash.replace(rep'#s=' + index)
  }

  let u = _spPageContextInfo.siteAbsoluteUrl + 
'/Pages/ItemPage.aspx' + 
location.search + location.hash
  window.open(u)
}

Calling that we will be using "ctx.CurrentItemIdx" in our display template and send in inside onclick.



4. When in the single item page, run the query on our search results web part

So we are in our new page. The simple hashtag of "#k=#s=15#l=1033" does not need any help, as soon as you got the right 's' value the search result webpart finds the right item, and as long as you pass the query text, either by 'k' or some other Query String or token method, you can now page the same items as in the previous page.

BUT if you pass that big #Default object, the webpart does not care (also not after page refresh)

I have decided to check the SP scripts to see whats up... 

1st I looked on the buttons. Paging button have this
onclick="$getClientControl(this).page(7);return Srch.U.cancelEvent(event);"
While refiner Apply button has this
onclick="Srch.Refinement.submitMultiRefinement('RefinableString149', $getClientControl(this), false, false);"

So I understood I am looking for something called Client Control.
Looking at the SP files f found a matching script file
 


Knowing SharePoint for a long long time, I already know that every .js file has its original un-minified version as ".debug.js" file (I think I just saw it some day in an On-Prem project while debugging)
So you can all go ahead and read what going on in search.clientcontrols.debug.js

While running with F3 (search next) with "query" as keyword I finally found around the exposed funtions this part
 
changeQueryTermfunction Srch_Result$changeQueryTerm(queryTerm) {
  if (!Srch.U.e(queryTerm)) {
      var $v_0 = new Srch.QueryState();
      $v_0.k = queryTerm;
      $v_0.s = 1;
      var $v_1 = new Srch.QueryEventArgs($v_0);
      $v_1.userAction = 0;
      this.raiseQueryReadyEvent($v_1);
  }
},

This fn has 'k' and 's', sounds like "$v_0" is our #Default obj, lets try it the console, and BANG! We got it!

We also found that this thing need its time. Being in _spBodyOnLoadFunctionNames was not enough nor 
AddPostRenderCallback. so I started an interval, that can be called with any of them.

let setSearchDefaultToken_intervalId = null;

function setSearchDefaultToken(){
  console.log('setSearchDefaultToken');

  let elem = document.querySelector("#Result")
  let cc = $getClientControl(elem)
  if (!cc || ! elem) {
    return false;
  }
  console.log('setSearchDefaultToken found elem and cc');

  //console.log('test settings :: ', document.querySelector("#Result"), cc );
  let x = JSON.parse(decodeURIComponent(location.hash).replace("#Default=",""))
  let v1 = new Srch.QueryEventArgs(x)
  cc.raiseQueryReadyEvent(v1)
  clearInterval(setSearchDefaultToken_intervalId)
}


    //somewhere in the code
    setSearchDefaultToken_intervalId = setInterval(setSearchDefaultToken250);



5. Taming an reusing the hover panel with the preview of the files

TBC







Comments

  1. Sharepoint Search Move To Another Page With Same Query And Filters >>>>> Download Now

    >>>>> Download Full

    Sharepoint Search Move To Another Page With Same Query And Filters >>>>> Download LINK

    >>>>> Download Now

    Sharepoint Search Move To Another Page With Same Query And Filters >>>>> Download Full

    >>>>> Download LINK MZ

    ReplyDelete

Post a Comment

Popular posts from this blog

OverTheWire[.com] Natas Walkthrough - JUST HINT, NO SPOILERS

SOLVED The item could not be indexed successfully because the item failed in the indexing subsystem

Asp.Net Ending Response options, Response.End() vs CompleteRequest()