Search results while typing

Hello,

I know this discussion has been closed but I was wondering if you could help me out.
I’ve be trying to follow the example but I’m getting a console error “Uncaught SyntaxError: Unexpected token < in JSON at position 0”.
When checking the network response I get from the input field I’m getting the full html site instead of the Json. I’m guessing that’s why I’m getting the error, but I can’t seem to detect where the problem is. I’m relatively new to kirby and json.

Any help would be much appreciated.

This is my routing configuration:

c::set('routes', array(
  array(
    'pattern' => '/kirby3/search?q=(:all)',
    'action' => function ($uri) {
        $query   = $uri;
        $results = site()->search($query)->toJson();
        return response::json(array(
            $results
        ));
    }
  )
));

And inside my footer my jquery:

var searchInput = $('#input-search');
var searchResultsWrapper = $('#wrapper-search-results');

$(searchInput).on(‘keyup’, function(e) {

  // I check if the length in the input is more than 3 characters
  if(searchInput.val().length > 3) {
      $.ajax({
          // build the url
          url: "/kirby3/search?q="+searchInput.val()+"",
          context: jQuery('#wrapper-search-results')
      })
      .done(function(data) {
      	console.log('someting');
          // convert the data to objects, console.log this to see 
          // how the object is build and which keys you can use
          var results = JSON.parse(data);
          // Flush the container
          searchResultsWrapper.html('');
          // loop trough the objects in results and display them
          jQuery.each(results, function(index, object) {
              var string = '<div class="content-box"><a href="'+object.url+'" class="full-link"></a><time class="content-box__datetime">'+object.content.date+'</time><h2 class="content-box__title">'+object.content.title+'</h2><p>'+object.content.intro+'</p></div>';   
              // Append the results to the container
              searchResultsWrapper.append(string);        
          });
      });
  } 

});

I think your pattern is wrong, “kirby3” is probably just the folder your Kirby project is in, so that should not be part of the pattern. Try this instead:

c::set('routes', array(
  array(
    'pattern' => 'search?q=(:all)',
    'action' => function ($query) {
        $results = site()->search($query)->toJson();
        return response::json(array(
            $results
        ));
    }
  )
));

Another issue is that query parameters are not allowed in the route pattern. You have to leave that out and can then get it with get('q') in your action function.

@lukasbestle is of course right, so your route should look like this:

c::set('routes', array(
  array(
    'pattern' => '(:all)/search',
    'method' => 'GET',
    'action' => function() {
        $query = get('q');

        $results = site()->search($query)->toJson();

        return response::json(array(
            $results
        ));
    }
  )
));

I’d also make the url more dynamic, so that you can move your site to a remote server without having to change the URL:

var url = window.location.href + "/search?q="+searchInput.val();
// ...
$.ajax({
            // build the url
            url: url,
            context: jQuery('#wrapper-search-results')
        })
1 Like

Thank you all for your support!
I configured the routing as @texnixe pointed out and modified the jquery and it’s working!
The only thing I changed was the url variable to include only the pattern. Then in the ajax method I added the input value since I wasn’t getting the complete url.

>  var searchUrl = window.location.href+"/search?q=";

> 	$(searchInput).on('keyup', function(e) {

> 	    if(searchInput.val().length > 3) {
> 	        $.ajax({
> 	            url: searchUrl+searchInput.val(),
> 	        })

Is it possible to add this solution to the cookbook section?

@mthiebou I’ll put it on the list.

I’ve made a vanilla Ajax solution.

<script>
function showResult(str) {
    if (str.length == 0) {
        document.getElementById("livesearch").innerHTML = "";
        return;
    }
    
    if (window.XMLHttpRequest) {
    // code for IE7+, Firefox, Chrome, Opera, Safari
    
    var xmlhttp = new XMLHttpRequest();
        
    } else {  // code for IE6, IE5
    xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
    }    
    
    xmlhttp.onreadystatechange = function() {
    if (this.readyState == 4 && this.status == 200) {
    document.getElementById("livesearch").innerHTML = this.responseText;
    }
    }

    xmlhttp.open("GET", "/ajax?q=" + str, true);
    xmlhttp.setRequestHeader('X-Requested-With','XMLHttpRequest');
    xmlhttp.send();
    
}
</script> 
    
 <input type="search" placeholder="Search website" autocomplete="off" spellcheck="false" name="q" onkeyup="showResult(this.value)">  

    
<p>Searchresults: </p> 
<div id="livesearch"></div>   
    
</div> 

3 Likes

@mthiebou Thanks for sharing :slight_smile: