I really wanted to have the ability to tag my blog posts. I am getting to the point now that there are enough of them now that they are a bit more tricky to navigate. Jekyll supports tagging, and it is actually pretty easy to use. You can add tags to any post by adding some meta data to the top of the file like so:
Then, it is really easy to collect all of the unique tags that you have across all of your posts in a template:
| first is important, otherwise you will likely get more than what you really want. That is about as much as Jekyll offers as far as tagging goes. The unfortunate thing about tags with Jekyll is that when you want to list everything for a specific tag you would be required to have a dedicated file for displaying that tag’s posts. I do not want that. I want something dynamic enough that I can easily add a new tag without having to do anything else to display that tag’s posts. That is where Ember.js came in for me.
I figured that I could build an Ember.js application that would deliver the dynamic functionality that I wanted which was not provided by Jekyll. The first step was somehow getting the data to this theoretical Ember application.
As I showed before, it is not hard to get all of the tags using vanilla Jekyll. My first step was to have Jekyll generate a
json file that contained all of the tags, plus each article with it’s tags. I would also need, in addition to the title of the article, the date it was published as well as a link to the full article.
Alright, I know that is a big mess, generating
json can be, but it does work correctly and generates something like this:
Now, having all of the tag information available via
json it can be consumed by an Ember application.
The handlebars templates for the ember application are fairly straight forward:
Just to quickly walk thought the templates, I’ve got the
div which is where the Ember app will live on the page. Then the default
outlet which is just a placeholder for the whole application, then there are 2 templates. One for the
index view which will display all of the tags and another for the
tag view which will list all of the articles for a given tag.
The most important thing that will definately trip you up when putting handlebars templates inside of a Jekyll template is that handlebars and Jekyll use similar syntax for template tags, which means handlebars templates need to be escaped. This can easily be done by wrapping handlebars templates in
raw tags like this:
The Ember application itself is fairly small, but there are a few tricky bits that I will discuss. The final application looks like this:
Lets dissect the
find method of
App.Tag object first. The core of this is a basic jquery
ajax call. We are hitting the
/tags/data.js url (which is generated using the Jekyll template discussed earlier). Then we are wrapping that ajax call with a promise using
Ember.RSVP.Promise then calling
resolve in the
reject in the
fail. When we call
resolve we are first building a list of
App.Tag objects with the results of the
ajax call. We will use those to display on the page.
We are using the
App.Tag objects returned from the
find method to display a list of tags in our
index template. In our handlebars
index template we have a
link-to to link to the
tag route for each tag. Then in our
model hook in our
Tag route we are doing a few different things. First we are making sure that we are setting
selected to true for the tag that the user chose. Second we are filtering all of the
App.Tag objects down to just the one that was selected.
The results of the
model hook will be used in the
tag handlebars template. In the
tag handlebars template we are displaying each article for the chosen tag. The other thing that is happening as a result of the
selected property being set in the
model hook is that the
index handlebars template will toggle the class of the
<li> tag used to display each tag so the most recently selected tag will display as being highlighted and the rest will not.
That is really all there is to it. If you are interested you can view my actual running source here.