Meteor JS (Part 7): Item Search

This is a post in a multiple part series on getting started with Meteor JS. If you don’t have Meteor JS installed you will want to start at  the first post in the series. Part 2 is where we start building the application.

If you would like to follow along I have tagged the git repository on Github at the starting point for this post. Here is the URL to the tag

https://github.com/dhirshjr/pricebook/releases/tag/v0.6.0

In this post we are going to add the email address of the currently logged in user to our layout. Then we are going add an item search feature. The way the search feature will work is by letting you enter a search term for each column. This will allow us to limit the number of records coming back.

So let’s get started.

Logged In User Email Address

In the last post we discussed authentication and authorization. We added a sign in button but forgot something very important. How do we know which user is logged in? We don’t. Thanks goes out to AlanB for calling this one out.

Javascript

First let’s create a UI helper that we can call from any template. This will allow us to place {{currentUserName}} anywhere we need to display the username.

Add the following code to the end of client/lib/helpers.js.

UI

Now let’s use the UI helper in our layout template.

Add the following to client/views/layouts/layout.html.

After you save you should start to see the email address of the currently logged in user, beside the sign out button, if you are signed in.

Item Search

We will be placing a search button in the header of the first column. When a user clicks the search button a filter field will appear in each column. All string type fields will use a regular expression search. All number type fields will use an exact search. For the query, all fields that are filled in will be combined together using an and operator. Below is an image of he finished product.

MeteorJSPart7FinshedProduct

Item Search Template

First, we are going to create a template to handle filtering a column. When we use this template we will use the following syntax.

Let’s create a file at client/views/items/itemsearch.html and add the following code.

Nothing really that interesting here other than value getting assigned from searchValue. We will get to see where that comes from when we get to itemsearch.js.

Next, let’s create a file at client/views/items/itemsearch.js and add the following code.

There is a lot going on in here. We are attaching an event on the key up of the .searchInput within the current template. Then, we are throttling it to only fire once every half second.

The event handler itself is taking in the event and template as arguments. Within the handler, we are checking for our session object. If one doesn’t exist we create an empty object. Next, we assign searchValue the value from the .searchInput within the template.

At this point we need to check if we got an empty string or not. If we didn’t get an empty string we need to look at our number parameter on the template. If it is a number just parse it as a number. If it isn’t a number just assign the string value of the input to our searchQuery object.

Now here is where things get interesting. At the point that the property is created it will always be on the searchQuery object. We need to get rid of empty properties because we don’t want to burden the server with doing a search on empty strings. So we delete the property by using the delete keyword.

Finally, we save the searchQuery to our session. What this event handler allows us to do is place as many item search templates as we have columns in our items collection.

All that is left is to create the helper that returns the value. This allows the item search template to survive a hot code push because session is preserved when a hot code push happens.

Finally let’s create a file at client/views/items/itemsearch.css and add the following code.

Here we are just saying hide the inputs by default. You might be wondering why I have used so many classes to define this rule? Originally I tried just using my filterInput class but Semantic UI had rules that were more specific than mine. In order to override them I had to create a rule with higher specificity. If you would like to know more about CSS specificity check out my post on the subject.

CSS: Specificity

Item Publication

Everything we have done so far has been on the client. We need to modify the allItems publication on the server side to take in our searchQuery object that we create on the client side. This is where the true beauty of Meteor starts to shine. All I have done on the client side is create an object in Javascript. And I just need to use it on the server side.

Modify server/publications/items/item.js by replacing the code with the following.

All we are doing here is just looping the properties of the searchQuery object and transforming them into a Mongo DB query. What is really cool about this is that it makes only the search results available to the UI. You will notice, in the next section, that we are not going to make any changes to how the list of items is generated. This is part of the reactive nature or Meteor JS.

Item List

Next, let’s modify client/views/items/itemlist.js by adding the following code. You will notice at this point that we have moved our subscription within a call to Tracker.autorun. This allows the subscription to update every time the Session searchQuery object changes. At the bottom we are adding an event handler to make our filter inputs appear.

All we need to now is to modify client/views/items/itemlist.html to use our new itemSearch template by adding the following code.

Finally, let’s create a  file at client/views/items/itemlist.css and add the following code. This just changes the cursor to a pointer on our search button.

Summary

In this post we added a pretty sophisticated search mechanism. There are better ways of doing search. Like using a Mongo DB fulltext index. But this is all we need for now. I may visit better ways of searching in a later post.

If you have any questions leave a comment on this blog or send me a tweet on twitter to @dhirshjr. And as always the code from this post is up on Github at the following URL.

https://github.com/dhirshjr/pricebook

4 thoughts on “Meteor JS (Part 7): Item Search”

  1. Another great article but it took me a while to understand the overall search procedure. Screen shots (as per Part 5) with some search criteria first, then with the filtered results would certainly help.
    The application works fine , the only hiccup is that on loading I get an exception message on the console for each heading property. eg
    Exception in template helper: TypeError: Cannot read property ‘store’ of undefined
    at Object.Template.itemsearch.helpers.searchValue (http://localhost:3000/pricebook.js?d924d2e278215bd9881bf0d425472fe4ccedc7ee:160:38)
    at http://localhost:3000/packages/blaze.js?efa68f65e67544b5a05509804bf97e2c91ce75eb:2727:16
    at http://localhost:3000/packages/blaze.js?efa68f65e67544b5a05509804bf97e2c91ce75eb:1606:16
    at Spacebars.call (http://localhost:3000/packages/spacebars.js?7f53771c84a2eafac2b561c9796dda0d8af8e7f5:171:18)
    at Spacebars.mustacheImpl (http://localhost:3000/packages/spacebars.js?7f53771c84a2eafac2b561c9796dda0d8af8e7f5:108:25)
    at Object.Spacebars.mustache (http://localhost:3000/packages/spacebars.js?7f53771c84a2eafac2b561c9796dda0d8af8e7f5:112:39)
    at Template.itemsearch.HTML.DIV.HTML.INPUT.value (http://localhost:3000/template.pricebook.js?4d5c963be8beba7e777873a6a3befc236ee519ce:355:24)
    at Object.Blaze._withCurrentView (http://localhost:3000/packages/blaze.js?efa68f65e67544b5a05509804bf97e2c91ce75eb:2043:12)
    at Blaze._HTMLJSExpander.def.visitAttribute (http://localhost:3000/packages/blaze.js?efa68f65e67544b5a05509804bf97e2c91ce75eb:1971:21)
    at HTML.TransformingVisitor.def.visitAttributes (http://localhost:3000/packages/htmljs.js?567eb96d5d22631c03d6aca6afa4c42f0d1295f2:228:44)

    Also, couple of typos: follwoing, searchValuie
    Thank you so much for very instructional article.

    1. Hi Alan,

      I wanted to personally thank you again for following along and providing the great feedback that you have provided.

      I have added an explanation of how the search feature is supposed to work and added a finished image. Also I have fixed the typos.

      Now about the exceptions.
      I have fixed the bug. It turns out that I needed to be checking if the session variable existed before trying to pull out the value. I have added a null check to both the session variable and the property. Thanks for pointing this out.

      Thanks,
      Douglas

  2. Thank you for an excellent series Doug.

    I am curious one thing though, your use of routes.js suggests you’re using iron router. I though that was being folded in by MDG in 1.2?

    Cheers

    1. Hi Joseph,

      Thank you for stopping by.

      It looks like MDG is creating their own routing library. I think for historical purposes I might leave Iron Router in this series. It will still be valid.

      I am thinking about doing a new series that might incorporate different packages. I will wait until meteor 1.2 is released since there are going to be a lot of changes. Let me know if you have any suggestions for the type of app you would like to see created in the new series.

      Thanks,
      Douglas

Leave a Reply

Your email address will not be published. Required fields are marked *