Live search for Umbraco frontend – using AngularJs and json content api

Everyone loves instant / live search, where a preview of the contents show up instantly as you write, right?

Update : http://joeriks-blog.azurewebsites.net/archive/a-prerelease-of-a-new-version-of-tapas-an-api-for-published-umbraco-content/
I wrote about an approach to create such a search quite a while ago using Examine. Now I like to write about an experimental, but working, approach that is faster than Examine and at the same time use a little bit of AngularJs.

Now – how is it even possible to be faster than Examine? Okay I cheat, I move the search to the client side, and get rid of the server call for each keypress / set of keypresses. Bad choice for sites with a fair amount of content? Well, if we take the Umbraco4 documentation as an example, last time I checked it was about 700kBs of data (in 236 markdown files). When we gzip compress that amount of text we should get about 175kBs. Which is similar in size as an ordinary – decently sized – image, and takes less than a second to download on a slow internet connection. For 236 pages of text. Let’s load that data on the initial page load, and perform the search with simple javascript functions.

For the actual search I’m going to use Umbraco 6 with the MVC CWS Starter kit , a little bit of AngularJs on the front end and a small json content api I call Tapas.

Install the mentioned packages. Then create a partial view called clientSideSearch.cshtml. Add the following code:

@inherits Umbraco.Web.Mvc.UmbracoTemplatePage

<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.1.5/angular.min.js"></script>
<script src="/scripts/clientsearch.js"></script><!-- scripts placed in partialview for simplicity -->

<div ng-app="liveSearchModule" ng-controller="SearchCtrl">

    <h1>Live search</h1>
    <input id="searchText" type="search" placeholder="live search..." ng-model="searchText" />

    <ul ng-if="searchText">
        <li ng-repeat="child in children | filter:searchText | limitTo: 10">
            <a href="{{child.NiceUrl}}">{{child.Name}}</a>
            <div ng-bind-html-unsafe="child.Properties.bodyText"></div>
        </li>
    </ul>
</div>

A few notes about the code. The Angular module and controller sets the scope in our html view. Then we use Angular built in directives ng-if and ng-repeat to filter the search results. Lastly we use Angular templating and the scoped objects to display the content, name, url and bodytext. The ng-bind-html-unsafe directive tells Angular to render the content as is, without encoding the html (as Html.Raw in Razor).

The “children” objects are returned by Tapas with a straight forward format shown in the docs for Tapas.

Add the render instruction inside your search view, “CWS-Search.cshtml” for example:

@Html.Partial("clientSideSearch")

Next create the /scripts/clientsearch.js script:

angular.module('liveSearchModule', [])
  .controller('SearchCtrl', function ($scope,$http) {
      $scope.children = $http.get('/umbraco/publishedcontent/nodes/getchildren?path=/'); // get all children from the root document
  });

This controller makes an ajax request (similar to $.getJSON / $.ajax) initially to get content from the content api, in this example all immediate children under root (path=”/”). The request returns a “promise” = an async result. Angular handles that automatically, and we do not need to figure out a way to render the content after the async is finished. The controller does not have any other functionality than to get data on initialization, later on the actual search is performed on the data in $scope.children.

And thats it!

livesearch

Enter one or more letters in the search box to see the articles with bodytext below. If you like to format the document differently simply change the template. Limit number of search items if you wish. If you like to extend this with pager and change to a server side based service it’s fairly easy aswell. Also we might want to search through the entire tree. If there’s interest I’ll write a follow up later on.

Advertisements

17 thoughts on “Live search for Umbraco frontend – using AngularJs and json content api

  1. Hey Jonas,
    Looks great, the only thing missing is the contents of the tapasClient JS as I would be curious to see what that is doing.

    I am curious to why you didnt use $http.get(‘/umbraco/tapas/GetChildren/’) or whatever URL you need to hit to get your JSON.

    Cheers,
    Warren 🙂

    • Hi Warren. The tapasclient.js is included in the tapas package, and is only a thin wrapper over $.getJSON – to simplify the use aswell as making the api explorable, it was intended for use outside of Angular to begin with. But indeed, I agree, $http makes the code clearer in this case. Thanks for your suggestion!

  2. Awesome! Tapas looks really nice!!

    Nice example!

    What would you see as “the limit” for when this approach would bot work? How much content?

    • Hi Markus, thanks 🙂 Well, I don’t know, I guess the only way is to try it. But text data is cheap and javascript done right is fast, so it should be able to handle quite a lot of data. Another good side of this is you can easily make it work offline, just by adding a manifest file. A drawback is we need to handle updates in a good way.

  3. Hi
    Great post thank you very much
    I have tried to implement it in my site but I keep getting this error(chrome dev tools):

    GET http://localhost:51021/umbraco/publishedcontent/nodes/children?path=/ 404 (Not Found) angular.js:7889
    (anonymous function) angular.js:7889
    A angular.js:7720
    h angular.js:7454
    A angular.js:10655
    A angular.js:10655
    (anonymous function) angular.js:10741
    g.$eval angular.js:11634
    g.$digest angular.js:11479
    g.$apply angular.js:11740
    (anonymous function) angular.js:1297
    d angular.js:3633
    Xb.c angular.js:1295
    Xb angular.js:1309
    Sc angular.js:1258
    (anonymous function) angular.js:20210
    fire jquery-2.0.3.js:2913
    self.fireWith jquery-2.0.3.js:3025
    jQuery.extend.ready jquery-2.0.3.js:398
    completed jquery-2.0.3.js:93

  4. Thanks Dan, and I’m sorry I did not respond to this earlier – I typo’ed the url – see more info about the correct urls at the github repository.

    I checked it with Umbraco 7 – and it works there aswell.

  5. I really like this. Thanks for sharing.
    I’m trying to use this in a test project, but i have a problem with this code.

    You use “/nodes/getchildren”, but that only gets the direct children. For a search option on a website that won’t be enough. We would have to get all descendants. (Also subitems & sub-subitems)
    I tried using “/nodes/getdescendantsandself”, but that doesn’t work.

    Can you help me out with this, and maybe many others, and extend your example with a option to search on deeper levels?

    Cheers, Rob

  6. Any chance you can reopen the blog post I cannot seem to get this to work 😦 with the above

    I can see the JSON file but when I start typing I get 2 blank bullet points I only have 1 child

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s