Meteor Capture

Simple search pattern

Learning through seeing code I personally find to be most rewarding, so here is a simple demonstration of a nice search pattern. This is a pretty common type of autocomplete style search you have no doubt seen before (say atmosphere for example).

There's a couple of useful things shown here:

  1. We're defining our search query in a file that's shared between client & server. This means that our search cursor is not repeated in our publication and on the client! You'll notice also that we define it on the collection, this is purely aesthetic.
  2. Escaping the regular expression is important.

1. Escape util

common/utils.js

RegExp.escape = function(s) {  
  return s.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
};

2. Our search cursor

common/collections/books.js

Books = new Mongo.Collection('books');

Books.search = function(query) {  
  return Books.find({
    name: { $regex: RegExp.escape(query), $options: 'i' }
  }, {
    limit: 20
  });
};

3. Publication

server/publications.js

Meteor.publish('booksSearch', function(query) {  
  check(query, String); 

  if (_.isEmpty(query))
    return this.ready();

  return Books.search(query);
});

4. Template

client/views/books.html

<template name="books">  
  <input type="text" placeholder="Search..." value="{{booksSearchQuery}}">
  {{#if searchResults.count}}
    <ul>
    {{#each searchResults}}
      <li>{{name}}</li>
    {{/each}}
    </ul>
  {{/if}}
</template>  

5. Template handling

client/views/books.js

Tracker.autorun(function() {  
  if (Session.get('booksSearchQuery'))
    Meteor.subscribe('booksSearch', Session.get('booksSearchQuery'));
});

Template.books.events({  
  'keyup [type=text]': function(event, template) {
    Session.set('booksSearchQuery', event.target.value);
  }
});

Template.books.helpers({  
  searchResults: function() {
    return Books.search(Session.get('booksSearchQuery'));
  },
  booksSearchQuery: function() {
    return Session.get('booksSearchQuery');
  }
});

Roundup

This could be further improved in many ways! A couple of ideas might be implementing a loading template which can be displayed by watching the ready() method on our subscription handle. Also we might wish to _.debounce our keypress event so that it's not fired too often.

comments powered by Disqus