Advertisement

What's This Meteor Thing?

by

This Cyber Monday Tuts+ courses will be reduced to just $3 (usually $15). Don't miss out.

Lately, there has been a considerable amount of buzz around a new web platform, called Meteor. In this article, I will explain what it is, and why you should consider it for your future applications!


First Things First

Don't think of Meteor as a package manager, because it is far more powerful than that!

Meteor is a JavaScript framework, built around many small packages - some of which you may already be using, like MongoDB or jQuery. But don't think of Meteor as a package manager, because it is far more powerful than that! Meteor customized these packages into what they refer to as "smart packages" that communicate seamlessly with one another.

Meteor is by far the easiest development environment to install, with just a one line command that installs a database, development server, and a command line program, which takes care of creating and deploying your applications. I'll show you how to install it in just a bit.

If I had to define, in short, how Meteor can help you, I would have to say that it is the speed at which you can develop your applications. Sites, which used to require thousands of lines of code, only take a few hundred in Meteor. It does this by combining three key core features:

  1. Meteor is "Realtime by Design"
  2. "Database Access" from the Client
  3. "Latency Compensation"

By combining these three features together the meteor staff have created a very powerful framework and a whole new approach to programming. Now let's see what each of these mean.


1 - "Realtime by Design"

In Meteor, you don't program routines and functions, you program page elements. It is very component-oriented, in that just instruct Meteor how something should work, and it will take care of updating the page in realtime. This means that you don't need to write any AJAX or DOM manipulation code, saving you a significant amount of time.

In this tutorial, I will be using Meteor as is, without customizing its packages. The default templating plugin for laying out your components is Handlebars. In Handlebars, you create templates for your components, and Meteor will process these at runtime and generate dynamic HTML. Let's build a Meteor application that takes an array of JSON objects, one for each product, and displays the name, price, and availability. To get started, I will install Meteor and create a new project.

First, open up a Terminal window and type the following commands:

	curl install.meteor.com | /bin/sh

	meteor create products
	
	cd products

Inside the project directory, you will find three files: a JavaScript, HTML, and CSS file. Open the HTML file, and replace its contents with the following:

<head>
  <title>Products</title>
</head>

<body>
  {{> Products}}
</body>

<template name="Products">
	{{#each ProductArr}}
		<div class="Product">
			<h2>{{Name}}</h2>
			<p>Price: ${{Price}}</p>
			{{#if this.InStock}}
				<p>This Item is in stock</p>
			{{else}}
				<p>This Item is currently sold out</p>
			{{/if}}
		</div>
	{{/each}}
</template>

Above, we've created a template for our products, which basically just cycles through each one and displays the name, price, and availability. Now, let's open up the JavaScript file and replace everything within the Meteor.is_client if statement:

	var Products = new Array(
			{ Name    :  "Screw Driver",
			  Price   :  "1.50",
			  InStock :  true },
			  
			{ Name    :  "Hammer",
			  Price   :  "3.00",
			  InStock :  false }
	);

	Template.Products.ProductArr = function(){
		return Products;
	};

Whatever is inside the Meteor.is_client section is run only on the client. Most of our code will be placed within here. The JavaScript is what you might expect: an array to hold the products, and the ProductsArr variable that we defined in the template. To test your application, simply type "meteor" in the Terminal, and Meteor will launch the development server for you to test your application.

So you might say that this is pretty cool, but it's essentially just the standard Handlebars functionality - and we've all seen this before. However, it's what Meteor is doing in the background that is the truly cool part. Meteor recognizes that this section of the page relies on the Products array, so it will monitor that variable and, anytime it changes, (i.e you add an item) Meteor will automatically update the page with your new changes... in realtime! That's not all; if you were to add an event handler to these products, you wouldn't have to start guessing which button the user pressed, by adding custom attributes or by reading the DOM, because Meteor calls the event on the object itself - so you have access to its properties.

To demonstrate this, let's add a confirmation alert, when a user clicks on a product. Add the following code after the previous function:

	Template.Products.events = {
		"click .Product" : function(){
			if(this.InStock)
				confirm("Would you like to buy a " + this.Name + " for " + this.Price + "$");
			else
				alert("That item is not in stock");
		}
	};

This function is called on the original object, not on the page element, thus allowing you to start working with it without first having to determine which product corresponds to the clicked element. Another thing worth pointing out is that we're using CSS rules, when declaring events in Meteor. This means using periods for classes, pound symbols for ids, and the tag's name for HTML elements.


2 - Database Everywhere

Meteor comes with a version of MongoDB that works both on the server and the client.

By default, Meteor comes with a version of MongoDB that works both on the server and the client. On the server, it works as you might expect it to, but the database on the client is more of a pseudo-database. What I mean by this is that Meteor has an API written to mimic the Mongo API, but for a custom database that is cached in memory on the client. This allows you to send subsets of data. For instance, if you only want the user to have certain rows, or you don't want to send the password column, Meteor allows you to simply "publish" the info you want, and Meteor will treat it as a database on the client, allowing you to make your application faster and more secure!

By putting the database on the client, you can feed the database straight into your HTML page. For instance, in the previous example, instead of getting the products from an array, we can feed in the products database. So anytime the database changes, your updates will be pushed in realtime to all the clients.

To integrate this into our application, first we have to add the database to the top of our application, before the is_client if statement, because the database is for both the client and the server. Add the following code:

	var Products = new Meteor.Collection("Products");

Next, you can delete the Products array that we created earlier, and modify the ProductsArr function to look like the following:

	Template.Products.ProductArr = function(){
		return Products.find({}, {sort: {Name: 1}});
	};

Another plus for having the database on the client is that it allows you to use MongoDB's sorting API to automatically sort the elements on the page at the database level, which, again, saves you that much more time, when developing your application. You can either add records in code or in your browser's console. Either way, you would use the insert command on the Products variable. Here is an example:

	Products.insert({Name : "Hammer", Price : 4.50, InStock : true});
	Products.insert({Name : "Wrench", Price : 2.70, InStock : true});
	Products.insert({Name : "Screw Driver", Price : 3.00, InStock : false});
	Products.insert({Name : "Drill", Price : 5.25, InStock : true});

I used Google Chrome's console to enter this code, though you can certainly accomplish this in your editor as well.


3 - Latency Compensation

Meteor will update your UI in realtime.

Lastly, we come to Meteor's latency compensation. By now, we know that we can define elements, connect them to a database, and Meteor will update your site automatically. But connecting your application so tightly to a database can pose a serious issue. If your application only changes when the database does, then there may be a bit of lag between when the user clicks something, to when the changes are pushed to the database, and returned to your application. This can make your site feel slower than it should.

Well, the Meteor team has already thought of this; they created what they refer to as "Latency Compensation." When you send something to the database, Meteor will immediately pretend as if it had received the new updates from the database, and update your UI in realtime. By doing this, Meteor doesn't need to wait for the database to update, and your users will see the changes immediately as they make them. On the rare occasion when your update doesn't reach the server, Meteor will reconcile your data and push the updates to the browser, without you needing to write a single line of code.

To finish up with this tutorial, let's add a shopping cart, for the purposes of viewing latency compensation in action. First, we add the HTML for the cart:

	<body>
  		{{> Products}}
		{{> Cart}}
	</body>

	<template name="Cart">
		<div id="Cart">
			<table>
				<tr>
					<th>Name</th>
					<th>Price</th>
					<th>Quantity</th>
					<th>Total</th>
				</tr>
				{{#each CartItems}}
					<tr>
						<td>{{Name}}</td>
						<td>${{Price}}</td>
						<td>{{Quantity}}</td>
						<td>${{Total}}</td>
					</tr>
				{{/each}}
				<tr>
					<td colspan="4">Total: ${{SubTotal}}</td>
				</tr>
		</div>
	</template>

Now, we'll add the necessary JavaScript to make this work:

	var Cart = new Meteor.Collection("Cart");
	
	Template.Cart.CartItems = function(){
		return Cart.find({}, {sort: {Name: 1}});
	};
	
	Template.Cart.Total = function(){
		return this.Price * this.Quantity;
	};
	
	Template.Cart.SubTotal = function(){
		var Items = Cart.find({});
		var Sum = 0;

		Items.forEach(function(Item){
			Sum += Item.Price * Item.Quantity;
		});
		return Sum;
	};

This JavaScript is fairly straight forward. The first line adds the Cart collection, the next function connects the database to the cart, the third function returns the total price for each item in the cart, and the final function returns the subtotal for the bottom of the cart.

The last thing we require, to make this a fully functional demo, is to modify the event we made for when the user clicks a product, and make it add the item to the cart. Here is the full event handler:

		Template.Products.events = {
		"click .Product" : function(){
			if(this.InStock)
			{
				if(Cart.find({Name : this.Name, Price : this.Price}).count() > 0)
				{
					if(confirm("Would you like to buy another " + this.Name))
						Cart.update(
							{ Name : this.Name, Price : this.Price },
							{ $inc : {Quantity : 1} });
				}
				else
				{
					if(confirm("Would you like to buy a " + this.Name + " for " + this.Price + "$"))
						Cart.insert({ Name : this.Name, Price : this.Price, Quantity : 1 });
				}
			}
			else
				alert("That item is not in stock");
		}
	};

And there you have it! A product page and a shopping cart in only a few lines of code. By structuring the framework in this manner, your code is not only shorter, but elegant. Unfortunately, in the version of Meteor at the time of this writing, "upserting" into the database has not yet been implemented, so I had to manually check if the product was already in the cart or not.


Deployment

Now that you have built your app, it's time to deploy it to the web. Meteor provides us with two options:

  • Use their free servers, which the Meteor staff have set up
  • Deploy it to any server that has NodeJS and MongoDB installed. This allows you to deploy your app to any server that you have Terminal access to.

Deploying to Meteor's Servers

Deploying to their free servers is easy. All you must do is type: "meteor deploy yourSitesName.meteor.com". This will provision a free hostname and upload your application to run there. You can also use this option with your own custom domain name, such as "YourSite.com," but then you'll need to modify your site's DNS settings to point to origin.meteor.com.

Deploying to Your Own Server

The other option is to run it on your own server, which you can do by typing: "meteor bundle." This will package all the necessary files that will be required to run. Then, you'll Need to setup your MongoDB database and NodeJS dependencies. The Meteor team have included a README in the package, when you bundle your application. This file will provide exact instructions to get your application up and running.

For an example of a complete site in Meteor, I created a demo site, called "Tasks;" you can view the source on GitHub here, or view the live demo at schedule.meteor.com. Special thanks to the guys at watracz.com for doing the design.


Conclusion

To Recap:

  • You don't write Ajax
  • No DOM manipulation
  • Database access on the client
  • Automatically realtime
  • Open Platform

Even though Meteor is still in its infancy (beta), there isn't anything you can't get around. The amount of time Meteor saves in your application justifies the rare occurrence where you might need to write a workaround. With a full release expected in less than a year, any current kinks or bugs will quickly become a thing of the past.

I hope you've enjoyed this tutorial; if you have any questions, feel free to leave a comment in the comment section below, and I'll do my best to help!

Advertisement