Search

A search app displaying a list of results.



Launch App


Description


Search is important to most web apps. If you have a database with more than, say 100 records, you will want to consider some search, and possibly sort and filter, facility on your site. Since our app has no access to a real server, we will be using a Mock server that returns a random number of records generated with the help of a quote from Cicero, a Roman philosopher.

The page has two <script> templates. The search-results-template renders all search results and the search-result-template renders an individual record. Just as we did in the DataEntry example, the template token markers were changed from <% =   %> to double braces {{ and }} using a simple _.templateSettings call.

The Search app code is below:

var Patterns = {
    // ** namespace pattern
    namespace: function (name) {

        // ** single var pattern
        var parts = name.split(".");
        var ns = this;

        // ** iterator pattern
        for (var i = 0, len = parts.length; i < len; i++) {

            // ** || idiom
            ns[parts[i]] = ns[parts[i]] || {};
            ns = ns[parts[i]];
        }

        return ns;
    }
};

// ** namespace pattern 
// ** revealing module pattern
// ** singleton pattern
Patterns.namespace("InAction").Search = (function () {

    // change template token markers to use double curly braces (just like Mustache):
    _.templateSettings = {
        interpolate: /\{\{(.+?)\}\}/g,
        evaluate: /\{\{(.+?)\}\}/g
    };

    // ** extend pattern
    // ** option hash idiom
    var Book = Backbone.Model.extend({
    });

    // ** extend pattern
    // ** option hash idiom
    var Books = Backbone.Collection.extend({
        model: Book,
        url: "search/:q"
    });

    // ** extend pattern
    // ** option hash idiom
    var Views = Backbone.View.extend({

        // ** chaining pattern
        template: _.template($('#search-results-template').html()),
        el: $("#searchresults"),

        // ** init pattern
        initialize: function (obj) {
            this.query = obj.query;

            this.books = new Books();
            // ** observer pattern
            this.books.on('reset', this.render, this); // will trigger render
            this.books.fetch({ data: { q: this.query } });
        },

        render: function (eventName) {
            this.$el.empty();
            // ** iterator pattern
            this.books.each(function (book) {
                this.$el.append(new View({ model: book }).render().el);
            }, this);

            return this;
        }
    });

    // ** extend pattern
    // ** option hash idiom
    var View = Backbone.View.extend({
        // ** chaining pattern
        template: _.template($('#search-result-template').html()),

        render: function (eventName) {
            this.$el.html(this.template(this.model.toJSON()));
            return this;
        }
    });

    // Random text helpers

    var randomInt = function (min, max) {
        return Math.floor(Math.random() * (max - min + 1)) + min;
    }

    // cicero: used in random string generator
    var cicero = "Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla pariatur?";
    var ciceroLen = cicero.length;

    // server Mock
    fauxServer.addRoute("searchBook", "search/:q", "GET", function (context) {
            
        var q = context.data.q;
        var count = randomInt(6, 35);

        var array = [];

        // ** iterator pattern
        for (var i = 0; i < count; i++) {
            var from = randomInt(1, ciceroLen - 31);
            var to = from + randomInt(10, 30);
            var append = cicero.substring(from, to).replace(/^\s+|\s+$/g, ''); // sub and trim
            array.push({ id: i, title: q + " " + append })
        }

        context.data = array;
        return context.data;
    });

    var start = function () {

        // focus on search text box and hook up enter keydown event
        // ** chaining pattern
        $("#search").focus().keydown(function (event) {  
            if (event.keyCode == 13) {
                $("#searchbutton").click();
            }
        });

        // button click triggers search
        // ** observer pattern
        $("#searchbutton").on('click', function () {
            var q = $("#search").val();
            if (q) {
                new Views({ query: q });
            } else {
                alert("Please enter a search string");
                $("#search").focus();
            }
        });

        // ** observer pattern
        $("#reset").on('mousedown', function () {
            // ** chaining pattern
            $("#search").val("").focus();
            $("#searchresults").empty();
        });
    }

    return { start: start };
}());
    
$(function () {

    // ** facade pattern
    Patterns.InAction.Search.start();
});

The patterns and idioms used in this code are:

  • || and && idiom
  • Option Hash idiom
  • Namespace pattern
  • Single var pattern
  • Module pattern
  • Extend pattern
  • Init pattern
  • Chaining pattern
  • Iterator pattern
  • Singleton pattern
  • Observer pattern
  • Façade pattern

All of these patterns have already been described in the previous examples. This shows that the same patterns are commonly used over and over again. Once you develop the skills to write patterns they will become second nature, almost as if they were native to the JavaScript language.


Launch App