skip to Main Content

I’m trying to develop a tabbed search results page using the Google Programmable Search Engine (PSE) and their JSON API in order to have the same appearance as Google’s hosted search engine, which shows search and images results in two tabs, i.e. like this sample engine https://cse.google.com/cse?cx=b67b93cd338f948e5

enter image description here

The hosted search, above, shows the results for the search term in both the Web and the Image tabs. That’s what I want to do with a search based on the JSON API.

I’m using this answer as a starting point for using the JSON API, Is there a working sample of the Google custom search rest API? and it works.

With the JSON API, I can show search results with the thumbnail and snippet, or only images, using the image only search.

My question: How do I show results from both types of searches at the same time in their respective tabs? Like the hosted search?

The problem I’m having is the hndlr(response) which appends the script to the document. How do I add two hndlrs? Or is that the wrong approach?

The hndlr JSON response shows the thumbnail and snippet with a URL like this:

https://www.googleapis.com/customsearch/v1?key=KEY&cx=CX&q=test&callback=hndlr

And this URL shows image only results when &searchType=image is appended to the URL string, like this:

https://www.googleapis.com/customsearch/v1?key=KEY&cx=CX&q=test&callback=hndlr&searchType=image

One problem is that the JSON response.items are not the same between the standard search and the image only search, so I can’t simply append &searchType=image to the URL.

Do I need to run two complete hndlr loops? But if so, how do I append each to the document body without conflicts and to display in each tab?

So how can I get both thumbnail and snippet results in the Search Results tab and image only results in the Image Results tab at the same time and for the same query?

I can’t do a JSFiddle, because the JSON API keys are limited to 100 queries, and the code references a URL, which won’t work in a Fiddle.

(CSS and some Javascript response.items omitted for clarity. Both HTML and Javascript are in the same index.html file)

index.html:

        <html>
        <head>
        <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet">
        <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js"></script>
        </head>
        
        <body>
    
       <form action="searchresults.html" id="cse-search-box">
            <div>
                <input class="" name="q" type="text"> 
                <input class="" type="submit">
            </div>
        </form>
        
            <ul class="nav nav-tabs" id="mytabs" role="tablist">
              <li class="nav-item" role="presentation">
                <a class="nav-link active" id="tab-0" data-bs-toggle="tab" href="#tabpanel-0" role="tab" aria-controls="tabpanel-0" aria-selected="true">Search Results</a>
              </li>
              <li class="nav-item" role="presentation">
                <a class="nav-link" id="tab-1" data-bs-toggle="tab" href="#tabpanel-1" role="tab" aria-controls="tabpanel-1" aria-selected="false">Image Results</a>
              </li>
            </ul>
            
            <div class="tab-content pt-5" id="tab-content">
            <div class="tab-pane active" id="tabpanel-0" role="tabpanel" aria-labelledby="tab-0">
            <div class="gsc-result-info" id="resultmeta"></div>
                 <div id="searchresults"></div>
            </div>
        
            <div class="tab-pane" id="tabpanel-1" role="tabpanel" aria-labelledby="tab-1">
            <div class="gsc-result-info" id="resultmeta"></div>
                 <div id="images"></div></div>
            </div>

<script> (Javascript below)

Javascript:

    function hndlr(response) {
    
            //Search results load time
            document.getElementById("resultmeta").innerHTML = "About " + response.searchInformation.formattedTotalResults + " results (" + response.searchInformation.formattedSearchTime + " seconds)";
    
            // Clear the divs first
            document.getElementById("searchresults").innerHTML = "";
            document.getElementById("images").innerHTML = "";
    
            // Loop through each item in search results
            for (var i = 0; i < response.items.length; i++) {
                var item = response.items[i];
                var content = "";
                var imagesonly = "";
    
    
            // Search Results output simplified for clarity
            // Title Link
                content += "<a class='gs-title' href='" + item.link + "'>" + item.htmlTitle + "</a><br />";
    
            // Thumbnail image for search results
                content += "<a href='" + item.link + "'><img src='" + item.pagemap.cse_thumbnail[0].src + "'></a>";
        
                }
    
            // Pagination
            var totalPages = Math.ceil(response.searchInformation.totalResults / 10);
            console.log(totalPages);
            var currentPage = Math.floor(start / 10 + 1);
            console.log(currentPage);
            var pageControls = "<div class='gsc-results'><div class='gsc-cursor-box gs-bidi-start-align' dir='ltr'><div class='gsc-cursor'>";
            //Page change controls, 10 max.
            for (var x = 1; x <= totalPages && x<=10; x++) {
                pageControls += "<div class='gsc-cursor-page";
                if (x === currentPage)
                pageControls += " gsc-cursor-current-page";
                var pageLinkStart = x * 10 - 9;
                pageControls+="'><a href='test.html?start="+pageLinkStart+"&q="+query+"'>"+x+"</a></div>";
            }
            pageControls += "</div></div></div>";
            document.getElementById("searchresults").innerHTML += pageControls;
            document.getElementById("images").innerHTML += pageControls;
        }
    
        //Get search text from query string.
        var query = document.URL.substr(document.URL.indexOf("q=") + 2);
        var start = document.URL.substr(document.URL.indexOf("start=") + 6, 2);
        if (start === "1&" || document.URL.indexOf("start=") === -1)
            start = 1;
    
        //Load the script src dynamically to load script with query to call.
        // DOM: Create the script element
        var gsearchresults = document.createElement("script");
        // set the type attribute
        gsearchresults.type = "application/javascript";
        // make the script element load file
        gsearchresults.src = "https://www.googleapis.com/customsearch/v1?key=KEY&cx=CX&start="+start+"&q=" +query +"&callback=hndlr";
        // finally insert the element to the body element in order to load the script
        document.body.appendChild(gsearchresults);


</script>
</body>
</html>

2

Answers


  1. "How do I show results from both types of searches at the same time in their respective tabs? Like the hosted search?"

    You have to make two separate requests to the API.
    This means using two variables to hold the different responses (for each search type).

    //# each request seems to get always json.txt but content is different
    //# depends if &searchtype=image is used, etc…

    //# 1) Initialise (with hidden until needed)
    
    var data_web = document.getElementById("searchresults");
    var data_img = document.getElementById("images");
        
    //# hide using CSS styles
    data_web.style.visibility = "hidden";
    data_img.style.visibility = "hidden";
    
    //# 2) Get responses
    
    var res_web = fetch("json.txt"); //# results from Web search 
    var res_img = fetch("json.txt"); //# results from Images search
    
    //# 3) Update Div containers as usual
    
    document.getElementById("searchresults").innerHTML += pageControls;
    document.getElementById("images").innerHTML += pageControls;
    
    //# 4) Show search type content as needed
    //# consider also removing the previous child when switching to new child
    
    data_web.style.visibility = "true";
    document.getElementById("div_for_results_preview").appendChild(data_web);
    //data_img.style.visibility = "true";
    //document.getElementById("div_for_results_preview").appendChild(data_img);
    

    PS: Will show testable demo soon (dealing with CORS issues on my example live demo)

    Login or Signup to reply.
  2. There’s probably a cleaner and more efficient way to do this, but this works by running two API queries and two item loops, and changing the name of the function and variable so they don’t collide. You’ll need to add your HTML markup in each loop, but the basics are here. Load Bootstrap CSS and Javascript as needed.

    test.html

    <html>
    <body>
    
    <form action="test.html" id="cse-search-box">
    <div>
        <input class="searchform" name="q" type="text"> 
        <input class="search" value="Search" type="submit">
    </div>
    </form>
    
    <ul class="nav nav-tabs" id="mytabs" role="tablist">
      <li class="nav-item" role="presentation">
        <a class="nav-link active" id="tab-0" data-bs-toggle="tab" href="#tabpanel-0" role="tab" aria-controls="tabpanel-0" aria-selected="true">Search Results</a>
      </li>
      <li class="nav-item" role="presentation">
        <a class="nav-link" id="tab-1" data-bs-toggle="tab" href="#tabpanel-1" role="tab" aria-controls="tabpanel-1" aria-selected="false">Image Results</a>
      </li>
    </ul>
    
    <div class="tab-content pt-2" id="tab-content">
    <div class="tab-pane active" id="tabpanel-0" role="tabpanel" aria-labelledby="tab-0">
    
    <div class="gsc-result-info" id="resultmeta"></div>
    <div id="searchresults"></div>
    
    <script>
    
        function hndlr(response) {
    
            document.getElementById("resultmeta").innerHTML = "About " + response.searchInformation.formattedTotalResults + " results";
    
            // Clear the div 
            document.getElementById("searchresults").innerHTML = "";
    
            // Loop through each item in search results
            for (var i = 0; i < response.items.length; i++) {
                var item = response.items[i];
                var content = "";
    
            // Title Link
                content += "<div class='gs-title-container'><a class='gs-title' href='" + item.link + "'>" + item.htmlTitle + "</a></div>";
    
            // Thumbnail image for search results
                content += "<div class='gs-image-container'><a class='gs-image' href='" + item.link + "'><img class='gs-image' src='" + item.pagemap.cse_thumbnail[0].src + "'></a></div>";
                
            // Snippet text
                content += "<div class='gs-snippet-container'>" + item.htmlSnippet + "</div>";
                document.getElementById("searchresults").innerHTML += content;
                }
    
            // Pagination
            var totalPages = Math.ceil(response.searchInformation.totalResults / 10);
            console.log(totalPages);
            var currentPage = Math.floor(start / 10 + 1);
            console.log(currentPage);
            var pageControls = "<div class='gsc-results'><div class='gsc-cursor-box gs-bidi-start-align' dir='ltr'><div class='gsc-cursor'>";
            //Page change controls, 10 max.
            for (var x = 1; x <= totalPages && x<=10; x++) {
                pageControls += "<div class='gsc-cursor-page";
                if (x === currentPage)
                    pageControls += " gsc-cursor-current-page";
                var pageLinkStart = x * 10 - 9;
                pageControls+="'><a href='test.html?start="+pageLinkStart+"&q="+query+"'>"+x+"</a></div>";
            }
            pageControls += "</div></div></div>";
            document.getElementById("searchresults").innerHTML += pageControls;
        }
    
        //Get search text from query string.
        var query = document.URL.substr(document.URL.indexOf("q=") + 2);
        var start = document.URL.substr(document.URL.indexOf("start=") + 6, 2);
        if (start === "1&" || document.URL.indexOf("start=") === -1)
            start = 1;
    
        //Load the script src dynamically to load script with query to call.
        // DOM: Create the script element
        var jsElm = document.createElement("script");
        // set the type attribute
        jsElm.type = "application/javascript";
        // make the script element load file
        jsElm.src = "https://www.googleapis.com/customsearch/v1?key=KEY&cx=CX&start="+start+"&q=" +query +"&callback=hndlr";
        // finally insert the element to the body element in order to load the script
        document.getElementById("searchresults").appendChild(jsElm)
    
    </script>
    
    
    <div class="tab-pane" id="tabpanel-1" role="tabpanel" aria-labelledby="tab-1">
    
    <div class="gsc-result-info" id="resultmetaimages"></div>
    <div id="imagesonly"></div>
    
    <script>
    
        function hndlrimages(response) {
    
            document.getElementById("resultmetaimages").innerHTML = "About " + response.searchInformation.formattedTotalResults + " results";
    
            // Clear the div 
            document.getElementById("imagesonly").innerHTML = "";
    
            // Loop through each item in search results
            for (var i = 0; i < response.items.length; i++) {
                var imageitem = response.items[i];
                var imagecontent = "";
    
            // Image only results 
                document.getElementById("imagesonly").innerHTML += "<div class='container images-only'><a href='" + imageitem.link + "'><img class='img-fluid' src='" + imageitem.link + "'></a></div></div>";
                }   
    
            // Pagination
            var totalPages = Math.ceil(response.searchInformation.totalResults / 10);
            var currentPage = Math.floor(start / 10 + 1);
            var pageControls = "<div class='gsc-results'><div class='gsc-cursor-box gs-bidi-start-align' dir='ltr'><div class='gsc-cursor'>";
            //Page change controls, 10 max.
            for (var x = 1; x <= totalPages && x<=10; x++) {
                pageControls += "<div class='gsc-cursor-page";
                if (x === currentPage)
                    pageControls += " gsc-cursor-current-page";
                var pageLinkStart = x * 10 - 9;
                pageControls+="'><a href='test.html?start="+pageLinkStart+"&q="+query+"'>"+x+"</a></div>";
            }
            pageControls += "</div></div></div>";
            document.getElementById("imagesonly").innerHTML += pageControls;
        }
    
        //Get search text from query string.
        var query = document.URL.substr(document.URL.indexOf("q=") + 2);
        var start = document.URL.substr(document.URL.indexOf("start=") + 6, 2);
        if (start === "1&" || document.URL.indexOf("start=") === -1)
            start = 1;
    
        //Load the script src dynamically to load script with query to call.
        // DOM: Create the script element
        var jsElm = document.createElement("script");
        // set the type attribute
        jsElm.type = "application/javascript";
        // make the script element load file
        jsElm.src = "https://www.googleapis.com/customsearch/v1?key=KEY&cx=CX&start="+start+"&q=" +query +"&searchType=image&callback=hndlrimages";
        // finally insert the element to the body element in order to load the script
        document.getElementById("imagesonly").appendChild(jsElm)
    
    </script>
    
    </body>
    </html>
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search