javascripthtmljekylllunrjs

How to open a new page with search results in Jekyll using w/ Lunr.js?


I'm having a bit of trouble trying to display the search result in a new page titled results.html using this guide here.

It seems as though its setup to display results on the page where the search is being made which isn't what I'm looking for.

What I'm trying to do is have a search box in index.html, which opens a new page after pressing a button that contains search results.

Currently any search that is made on any page, just shows the results there.

_includes/search-lunr.html

<script src="/js/lunr.js"></script>

<script>
{% assign counter = 0 %}
var documents = [{% for page in site.pages %}{% if page.url contains '.xml' or page.url contains 'assets' %}{% else %}{
    "id": {{ counter }},
    "url": "{{ site.url }}{{ page.url }}",
    "title": "{{ page.title }}",
    "body": "{{ page.content | markdownify | replace: '.', '. ' | replace: '</h2>', ': ' | replace: '</h3>', ': ' | replace: '</h4>', ': ' | replace: '</p>', ' ' | strip_html | strip_newlines | replace: '  ', ' ' | replace: '"', ' ' }}"{% assign counter = counter | plus: 1 %}
    }, {% endif %}{% endfor %}{% for page in site.without-plugin %}{
    "id": {{ counter }},
    "url": "{{ site.url }}{{ page.url }}",
    "title": "{{ page.title }}",
    "body": "{{ page.content | markdownify | replace: '.', '. ' | replace: '</h2>', ': ' | replace: '</h3>', ': ' | replace: '</h4>', ': ' | replace: '</p>', ' ' | strip_html | strip_newlines | replace: '  ', ' ' | replace: '"', ' ' }}"{% assign counter = counter | plus: 1 %}
    }, {% endfor %}{% for page in site.posts %}{
    "id": {{ counter }},
    "url": "{{ site.url }}{{ page.url }}",
    "title": "{{ page.title }}",
    "body": "{{ page.date | date: "%Y/%m/%d" }} - {{ page.content | markdownify | replace: '.', '. ' | replace: '</h2>', ': ' | replace: '</h3>', ': ' | replace: '</h4>', ': ' | replace: '</p>', ' ' | strip_html | strip_newlines | replace: '  ', ' ' | replace: '"', ' ' }}"{% assign counter = counter | plus: 1 %}
    }{% if forloop.last %}{% else %}, {% endif %}{% endfor %}];

var idx = lunr(function () {
    this.ref('id')
    this.field('title')
    this.field('body')

    documents.forEach(function (doc) {
        this.add(doc)
    }, this)
});

function lunr_search(term) {
    document.getElementById('lunrsearchresults').innerHTML = '<ul></ul>';
    if(term) {
        document.getElementById('lunrsearchresults').innerHTML = "<p>Search results for '" + term + "'</p>" + document.getElementById('lunrsearchresults').innerHTML;
        //put results on the screen.
        var results = idx.search(term);
        if(results.length>0){
            //console.log(idx.search(term));
            //if results
            for (var i = 0; i < results.length; i++) {
                // more statements
                var ref = results[i]['ref'];
                var url = documents[ref]['url'];
                var title = documents[ref]['title'];
                var body = documents[ref]['body'].substring(0,160)+'...';
                document.querySelectorAll('#lunrsearchresults ul')[0].innerHTML = document.querySelectorAll('#lunrsearchresults ul')[0].innerHTML + "<li class='lunrsearchresult'><a href='" + url + "'><span class='title'>" + title + "</span><br /><span class='body'>"+ body +"</span><br /><span class='url'>"+ url +"</span></a></li>";
            }
        } else {
            document.querySelectorAll('#lunrsearchresults ul')[0].innerHTML = "<li class='lunrsearchresult'>No results found...</li>";
        }
    }
    return false;
}
</script>

<style>
    .lunrsearchresult .title {color: #d9230f;}
    .lunrsearchresult .url {color: silver;}
    .lunrsearchresult a {display: block; color: #777;}
    .lunrsearchresult a:hover, .lunrsearchresult a:focus {text-decoration: none;}
    .lunrsearchresult a:hover .title {text-decoration: underline;}
</style>


<form onSubmit="return lunr_search(document.getElementById('lunrsearch').value);">
    <p><input type="text" class="form-control" id="lunrsearch" name="q" maxlength="255" value="" placeholder="Search via Lunr.js" /></p>
</form>
<div id="lunrsearchresults">
    <ul></ul>
</div>

_layout/index.html

{% include search-lunr.html %}

The only thing I could think of was adding an action to the form which than opens the _layout/results.html which really doesn't change anything.

Any help would be appreciated. Thanks.


Solution

  • If you want the search results only on a separate page, you'll want the search form to have an action that points to it. The term will be passed to that page, which can then process it and display the search results.

    This template demonstrates this exact flow:

    It's a pretty good solution since your site viewers only have to load and run that code if they perform a search, which can be a substantial saving with a reasonably sized index.


    To replicate it roughly with your code above:

    1. Remove {% include search-lunr.html %} from your index.html.

    2. Have this on index.html:

      <form action="{{ site.baseurl }}/search/" method="get">
        <input type="text" name="q">
        <input type="submit" value="Search">
      </form>
      
    3. Then in your search.html:

      ...
      {% include search-lunr.html %}
      
      <script>
        function getQueryVariable(variable) {
          var query = window.location.search.substring(1),
            vars = query.split("&");
      
          for (var i = 0; i < vars.length; i++) {
            var pair = vars[i].split("=");
      
            if (pair[0] === variable) {
              return decodeURIComponent(pair[1].replace(/\+/g, '%20')).trim();
            }
          }
        }
      
        var query = decodeURIComponent((getQueryVariable("q") || "").replace(/\+/g, "%20"));
        lunr_search(query);
      </script>
      ...