9 min read

If you are like me, a JavaScript full-stack developer, your choices of technology might be limited when dealing with modern app/webapp development. You could choose a MEAN stack (MongoDB, Express, AngularJS, and Node.js), learn all four of these technologies in order to mix and match, or employ some ready frameworks, like DerbyJS. However , none of them provide you with the one-stop shop experience like Meteor, which stands out among the few on the canvas.

What is Meteor?

Meteor is an open-source “platform” (more than a framework) in pure JavaScript that is built on top of Node.js, facilitating via DDP protocol and leveraging MongoDB as data storage.

It provides developers with the power to build a modern app/webapp that is equipped with production-ready, real-time (reactive), and cross-platform (web, iOS, Android) capabilities. It was designed to be easy to learn, even for beginners, so we could focus on developing business logic and user experience, rather than getting bogged down with the nitty-gritty of learning technologies’ learning curve.

Your First Real-time App: Vote Me Up!

Below, we will be looking at how to build one reactive app with Meteor within 30 mins or less.

Step 1: Installation (3-5 Mins)

For OS X or Linux developers, head over to the terminal and install the official release from Meteor.

$ curl https://install.meteor.com/ |sh

For Windows developers, please download the official installer here.

Step 2: Create an app (3-5 mins)

After we have Meteor installed, we now can create new app simply by:

$ meteor create voteMeUp

This will create a new folder named voteMeUp under the current working directory. Check under the voteMeUp folder — we will see that three files and one folder have been created.

voteMeUp/
    .meteor/
    voteMeUp.html
    voteMeUp.css

.meteor is for internal use. We should not touch this folder. The other three files are obvious enough even for beginners — the HTML markup, stylesheet, and one JavaScript that made the barebone structure one can get for web/webapp development.

The default app structure tells us that Meteor gives us freedom on folder structure. We can organise any files/folders we feel appropriate as long as we don’t step onto the special folder names Meteor is looking at.

Here, we will be using a basic folder structure for our app. You can visit the official documentation for more info on folder structure and file load order.

voteMeUp/
    .meteor/
    client/
        votes/
            vote.html
            vote.js
        main.html
    collections/
        votes.js
    server/
        presets.js
        publications.js

Meteor is a client-database-server platform. We will be writing codes for client and server independently, communicating through the reactive DB drivers API, publications, and subscriptions.

For a brief tutorial, we just need to pay attention to the behaviour of these folders

  • Files in client/ folder will run on client side (user browser)
  • Files in server/ folder will run on server side (Node.js server)
  • Any other folders, i.e. collections/ would be run on both client and server

Step 3: Add some packages (< 3 mins)

Meteor is driven by an active community, since developers around the world are creating reusable packages to compensate app/webapp development. This is also why Meteor is well-known for rapid prototyping.

For brevity’s sake, we will be using packages from Meteor: underscore. Underscore is a JavaScript library that provides us some useful helper functions, and this package provided by Meteor is a subset of the original library.

$ meteor add underscore

There are a lot useful packages around; some are well maintained and documented. They are developed by seasoned web developers around the world. Check them out:

Step 3: Start the server (< 1 min)

Start the server simply by:

$ meteor

Now we can visit site http://localhost:3000. Of course you will be staring at a blank screen! We haven’t written any code yet. Let’s do that next.

Step 4: Write some code (< 20 Mins)

As you start to write the first line of code, by the time you save the file, you will notice that the browser page will auto reload by itself. Thanks to the hot code push mechanism built-in, we don’t need to refresh the page manually.

Database Collections

Let’s start with the database collection(s). We will keep our app simple, since we just need one collection, votes, that we will put it in collections/votes.js like this:

Votes = newMongo.Collection('votes');

All files in the collections/ folder run on both the client and the server side. When this line of code is executed, a mongo collection will be established on the server side. On the client side, a minimongo collection will be established. The purpose of the minimongo is to reimplement the MongoDB API against an in-memory JavaScript database. It is like a MongoDB emulator that runs inside our client browser.

Some preset data

We will need some data to start working with. We can put this in server/presets.js. These are just some random names, with vote count 0 to start with.

if (Votes.find().count() === 0) {
    Votes.insert({
        name: "Janina Franny",
        voteCount: 0
    });

    Votes.insert({
        name: "Leigh Borivoi",
        voteCount: 0
    });

    Votes.insert({
        name: "Amon Shukri",
        voteCount: 0
    });

    Votes.insert({
        name: "Dareios Steponas",
        voteCount: 0
    });

    Votes.insert({
        name: "Franco Karl",
        voteCount: 0
    });
}

Publications

Since this is for an educational purpose, , we will publish (Meteor.publish()) all the data to the client side under server/publications.js. You most likely would not do this for a production application.

Planning for publication is one major step in Meteor app/webapp development, so we don’t want to publish too little or too much data over to client. Just enough data is what we always keep an eye out for.

Meteor.publish('allVotes', function() {
    return Votes.find();
});

Subscriptions

Once we have the publication in place, we can start to subscribe to them by the name, allVotes, as shown above in the publication.

Meteor provides template level subscription, which means we could subscribe to the publication when a template is loaded, and get unsubscribed when the template is destroyed.

We will be putting in our subscription under client/votes/votes.js, (Meteor.subscribe()).

onCreated is a callback when the template name votes is being created.
Template.votes.onCreated(function() {
    Meteor.subscribe('allVotes');    
});

The votes template put in client/votes/votes.html would be some simple markup such as the following:

<template name="votes">
    <h2>All Votes</h2>

    <ul>
        {{#each sortedVotes}}
            <li>{{name}} ({{voteCount}}) <button class="btn-up-vote">Up Vote</button></li>
        {{/each}}
    </ul>

    <h3>Total votes: {{totalVotes}}</h3>
</template>

If you are curious what those markups are with {{ and }}, enter Meteor Blaze, which is a powerful library for creating live-updating on client side. Similar to AngularJS and React, Blaze serves as the default front-end templating engine for Meteor, but it is simpler to use and easier to understand.

The Main Template

There must be somewhere to start our application. client/main.html is the place to kickoff our template(s).

<body>
    {{> votes}}
</body>

Helpers

In order to show all of our votes we will need some helper functions. As you can see from the previous template, {{#each sortedVotes}}, where a loop should happen and print out the names and their votes in sorting order {{totalVotes}}, which is supposed to show the total vote count.

We will put this code into the same file we have previously worked on:

client/votes/votes.js, and the complete code should be:
Template.votes.onCreated(function() {
    Meteor.subscribe('allVotes');
});

Template.votes.helpers({
    'sortedVotes': function() {
        return Votes.find({}, {
            sort: {
                voteCount: -1
            }
        })
    },

    'totalVotes': function() {
        var votes = Votes.find();

        if (votes.count() > 0) {
            return _.reduce(votes.fetch(), function(memo, obj) {
                return memo + obj.voteCount;
            }, 0);
        }
    }
});

Sure enough, the helpers will return all of the votes, sorted in descending order (the larger number on top), and returning the sum (reduce – function provided by underscrore) of votes.

This is all we need to show the vote listing. Head over to the browser, and you should be seeing the listing on-screen!

Events

In order to make the app useful and reactive we need an event to update the listing on the fly when someone votes on the names. This can be done easily with an event binding to the ‘Up Vote’ button. We will be adding the event handler in the same file: client/votes/votes.js

Template.votes.onCreated(function() {
    Meteor.subscribe('allVotes');
});

Template.votes.helpers({
    'sortedVotes': function() {
        return Votes.find({}, {
            sort: {
                voteCount: -1
            }
        })
    },

    'totalVotes': function() {
        var votes = Votes.find();

        if (votes.count() > 0) {
            return _.reduce(votes.fetch(), function(memo, obj) {
                return memo + obj.voteCount;
            }, 0);
        }
    }
});

Template.votes.events({
    'click .btn-up-vote': function() {
        Votes.update({
            _id: this._id
        }, {
            $inc: {
                voteCount: 1
            }
        });
    }
});

This new event handler just did a quick and dirty update on the Votes collections, by field name _id.

Each event handler will have this pointing to the current template context — i.e. the {{#each}} in the template indicates a new context. So this._id will return the current _id of each record in the collection.

Step 5: Done. Enjoy your first real-time app!

You can now visit the site with different browsers/tabs open side by side. Action on one will trigger the reactive behavior on the other. Have fun voting!

Conclusion

By now, we can see how easily we can build a fully functional real-time app/webapp using Meteor. With “great power comes great responsibility[RJ8] ” (pun intended), and proper planning/structuring for our app/webapp is of the utmost importance once we have empowered by these technologies. Use it wisely and you can improve both the quality and performance of your app/webapp.

Try it out, and let me know if you are sold.

Resources:

Want more JavaScript content? Look no further than our dedicated JavaScript page

About the Author

Ken Lee is the co-found of Innomonster Pte. Ltd. (http://innomonster.com/), a specialized website/app design & development company based in Singapore. He has eight years of experience in web development, and is passionate about front-end and JS full-stack development. You can reach him at [email protected].

LEAVE A REPLY

Please enter your comment!
Please enter your name here