w3resource

Build an app with Meteor

What is Meteor

"A better way to build apps" that is what Open Source Web Platform Meteor promises. Let's have a look on the salient features of this Web framework.

All JavaScript. The same code you use on client side can be used to query database on server. That's excellent. You can maintain a single code base and can use it on both client and server side. Meteor runs on top of node.js and uses MongoDb database.

Applications which act in realtime. Applications developed with Meteor can handle real time communication using Distributed Data Protocol (DDP). On modern browsers it uses WebScoket and Ajax on a bit dated ones. In either cases, users end up with live realtime data without the page being refreshed.

Powerful data synchronization. Your client code can directly access database.

Making up delay. Say, a user wants to update some data, either the updates are rendered immediately or failing that, client responds immediately.

Realtime code update. You can update code even when users are online. As soon as you distribute the new code, updates are available on each browser frame with the app opened.

Code Security. You can make the sensitive code run in a privileged environment.

One stop application bundle. You can compile the entire code with a single command and then untar it. Then with a single command you give it a go. The entire application bundle is with you.

Interoperability. Thanks to DDP, connect your app with mobile apps, RDBMS and so on.

Smart Packages. These are little programs to append code to your client, server or hook into the bundler.

Let's build

In this tutorial we will build a simple Link submit app with Meteor. To begin with we will see how to install meteor.

Install Meteor

On a linux or mac, run the following command on terminal

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

Install Meteor

There is an unoffcial windows version available, you can download it from https://copy.com/WmreTgERHJEd/Meteor_0.6.3.1-rev4.msi?download=1. It is a MSI package.

Create App

Once installed, you can create an App with the following command form terminal.

meteor create LinkStore

Create an app

Once you have created an app, a HTMl, a CSS and a JS file is created, along with a meteor directory. Following shows the directory structure created.

 
.
|-- LinkStore.css
|-- LinkStore.html
|-- LinkStore.js
`-- .meteor
    |-- .gitignore
    |-- local
    |   |-- build
    |   |   |-- app
    |   |   |   |-- LinkStore.js
    |   |   |   `-- packages
    |   |   |       |-- autopublish
    |   |   |       |   `-- autopublish.js
    |   |   |       |-- check
    |   |   |       |   `-- match.js
    |   |   |       |-- deps
    |   |   |       |   `-- deps.js
    |   |   |       |-- ejson
    |   |   |       |   |-- base64.js
    |   |   |       |   `-- ejson.js
    |   |   |       |-- handlebars
    |   |   |       |   `-- parse.js
    |   |   |       |-- insecure
    |   |   |       |   `-- insecure.js
    |   |   |       |-- json
    |   |   |       |   `-- json2.js
    |   |   |       |-- livedata
    |   |   |       |   |-- crossbar.js
    |   |   |       |   |-- livedata_common.js
    |   |   |       |   |-- livedata_connection.js
    |   |   |       |   |-- livedata_server.js
    |   |   |       |   |-- node_modules -> /home/ritwik/.meteor/packages/livedata/bb17bb363041eff8aa0300e505770970d07129b4/.npm/node_modules
    |   |   |       |   |-- server_convenience.js
    |   |   |       |   |-- stream_client_common.js
    |   |   |       |   |-- stream_client_nodejs.js
    |   |   |       |   |-- stream_server.js
    |   |   |       |   `-- writefence.js
    |   |   |       |-- logging
    |   |   |       |   `-- logging.js
    |   |   |       |-- meteor
    |   |   |       |   |-- dynamics_nodejs.js
    |   |   |       |   |-- errors.js
    |   |   |       |   |-- fiber_helpers.js
    |   |   |       |   |-- helpers.js
    |   |   |       |   |-- server_environment.js
    |   |   |       |   |-- setimmediate.js
    |   |   |       |   |-- timers.js
    |   |   |       |   |-- url_common.js
    |   |   |       |   `-- url_server.js
    |   |   |       |-- minimongo
    |   |   |       |   |-- diff.js
    |   |   |       |   |-- minimongo.js
    |   |   |       |   |-- modify.js
    |   |   |       |   |-- objectid.js
    |   |   |       |   `-- selector.js
    |   |   |       |-- mongo-livedata
    |   |   |       |   |-- collection.js
    |   |   |       |   |-- local_collection_driver.js
    |   |   |       |   |-- mongo_driver.js
    |   |   |       |   |-- node_modules -> /home/ritwik/.meteor/packages/mongo-livedata/d113484af05cea7326b8ca67d8157650816e95aa/.npm/node_modules
    |   |   |       |   `-- remote_collection_driver.js
    |   |   |       |-- ordered-dict
    |   |   |       |   `-- ordered_dict.js
    |   |   |       |-- past
    |   |   |       |   `-- past.js
    |   |   |       |-- random
    |   |   |       |   `-- random.js
    |   |   |       |-- routepolicy
    |   |   |       |   `-- routepolicy.js
    |   |   |       |-- startup
    |   |   |       |   `-- startup_server.js
    |   |   |       `-- underscore
    |   |   |           `-- underscore.js
    |   |   |-- app.html
    |   |   |-- app.json
    |   |   |-- dependencies.json
    |   |   |-- main.js
    |   |   |-- README
    |   |   |-- server
    |   |   |   |-- .bundle_version.txt
    |   |   |   |-- node_modules -> /home/ritwik/.meteor/tools/cc18dfef9e/lib/node_modules
    |   |   |   `-- server.js
    |   |   `-- static_cacheable
    |   |       |-- LinkStore.css
    |   |       |-- LinkStore.js
    |   |       |-- packages
    |   |       |   |-- check
    |   |       |   |   `-- match.js
    |   |       |   |-- deps
    |   |       |   |   `-- deps.js
    |   |       |   |-- domutils
    |   |       |   |   `-- domutils.js
    |   |       |   |-- ejson
    |   |       |   |   |-- base64.js
    |   |       |   |   `-- ejson.js
    |   |       |   |-- handlebars
    |   |       |   |   `-- evaluate.js
    |   |       |   |-- jquery
    |   |       |   |   `-- jquery.js
    |   |       |   |-- json
    |   |       |   |   `-- json2.js
    |   |       |   |-- livedata
    |   |       |   |   |-- client_convenience.js
    |   |       |   |   |-- livedata_common.js
    |   |       |   |   |-- livedata_connection.js
    |   |       |   |   |-- sockjs-0.3.4.js
    |   |       |   |   |-- stream_client_common.js
    |   |       |   |   `-- stream_client_sockjs.js
    |   |       |   |-- liverange
    |   |       |   |   `-- liverange.js
    |   |       |   |-- logging
    |   |       |   |   `-- logging.js
    |   |       |   |-- meteor
    |   |       |   |   |-- client_environment.js
    |   |       |   |   |-- dynamics_browser.js
    |   |       |   |   |-- errors.js
    |   |       |   |   |-- fiber_stubs_client.js
    |   |       |   |   |-- helpers.js
    |   |       |   |   |-- setimmediate.js
    |   |       |   |   |-- timers.js
    |   |       |   |   `-- url_common.js
    |   |       |   |-- minimongo
    |   |       |   |   |-- diff.js
    |   |       |   |   |-- minimongo.js
    |   |       |   |   |-- modify.js
    |   |       |   |   |-- objectid.js
    |   |       |   |   `-- selector.js
    |   |       |   |-- mongo-livedata
    |   |       |   |   |-- collection.js
    |   |       |   |   `-- local_collection_driver.js
    |   |       |   |-- ordered-dict
    |   |       |   |   `-- ordered_dict.js
    |   |       |   |-- past
    |   |       |   |   `-- past.js
    |   |       |   |-- preserve-inputs
    |   |       |   |   `-- preserve-inputs.js
    |   |       |   |-- random
    |   |       |   |   `-- random.js
    |   |       |   |-- reactive-dict
    |   |       |   |   `-- reactive-dict.js
    |   |       |   |-- reload
    |   |       |   |   `-- reload.js
    |   |       |   |-- session
    |   |       |   |   `-- session.js
    |   |       |   |-- spark
    |   |       |   |   |-- convenience.js
    |   |       |   |   |-- patch.js
    |   |       |   |   |-- spark.js
    |   |       |   |   `-- utils.js
    |   |       |   |-- startup
    |   |       |   |   `-- startup_client.js
    |   |       |   |-- templating
    |   |       |   |   `-- deftemplate.js
    |   |       |   |-- underscore
    |   |       |   |   `-- underscore.js
    |   |       |   `-- universal-events
    |   |       |       |-- events-ie.js
    |   |       |       |-- events-w3c.js
    |   |       |       `-- listener.js
    |   |       `-- template.LinkStore.js
    |   `-- db
    |       |-- local.0
    |       |-- local.ns
    |       |-- mongod.lock
    |       `-- _tmp
    |-- packages
    `-- release

56 directories, 110 files

Now, moving to the app directory, you may run the Meteor with following command

meteor

running an app

Pointing your browser to localhost:3000 shows following

Running on browser

Adding packages

Meteor allows you add packages, piece of software to the app. For this app, we are going to use Twitter Bootstrap for styling, so we will ad Bootstrap package.

So, we have added

For styling, we want to use Twitter Bootstrap, so, we have added bootstrap package.

meteor add bootstrap

Meteot add Bootstrap

Creating markup

Meteor works on templating system. That is, you have static HTML and dynamic data fills the page where required. So we will replace the existing markup of LinkStore.html with following

<head>
    <title>Demo LinkStore app</title>
</head>
 
<body>
    <div class="container-fluid">
    <div class="row-fluid">
    <div class="span12">
    <h1>Add your favorite link</h1>
    </div>
    </div> 
    <div class="row-fluid">
    <div class="span8">
    {{> LinksTemplate }}
    </div>
    <div class="span4">
    {{> LinksForm }}
    </div>
    </div>
    </div>
</body>

So, we have created a simple two column fluid layout (after Bootstrap) and we have added are going to add two templates 'LinksTemplate' which will be used for displaying list of links and 'LinksForm' which is for adding new links.

Notice that we don't need any doctype and other stuff usually we put under head here.

Now we will create markup for 'LinksTemplate' template and append that after body of the LinkStore.html file.

<template name="LinksTemplate">
<ul>
    {{#each links}}    
	<li>       
	 {{url}}    
	</li>    {{/each}}    
	</ul>
</template>

By default, Meteor uses the Handlebars templating library. In the LinksTemplate above, Handlebars is used to loop through each of the links using {{#each}}…{{/each}} and display the title for each links using {{url}}.

This is how the markup for our another template 'LinksForm' will look like. This will also be added to the LinksStore.html file.

<template name="LinksForm">
    <fieldset>
    <legend>Add New Links</legend>
    <form class="form-horizontal">
        <div>
            <label>
                url:
                <input id="url" />
            </label>
        </div>
        <div>
            <label>
                Description:
                <input id="description" />
            </label>
        </div>
        <div>
            <input type="submit" value="Add new links" class="btn btn-large btn-success "/>
        </div>
    </form>
    </fieldset>
</template>

Now we will take our js file LinkStore.js and replace the existing code with following (to begin with).

// Declare client links collection
Links = new Meteor.Collection("links");
if (Meteor.isClient) {
// Bind LinksTemplate to Links collection
Template.LinksTemplate.links = function () {
    return Links.find();
};
}

To add links through links form, we will append the following code to the js file now

if (Meteor.isClient) {
// Handle LinksForm events
Template.LinksForm.events = {
    'submit': function (e, tmpl) {
        // Don't postback
        e.preventDefault();
 
        // create the new link
        var newLink = {
            url: tmpl.find("#url").value,
            description: tmpl.find("#description").value
        };
 
        // add the link to the db
        Links.insert(newLink);
    }
};
}

The Template.LinksForm.events property contains an event map which maps event names to handlers. In this case, form submit event is mapped to an anonymous function which handles the event.

In the event handler, first by calling e.preventDefault() the post is stopped, as happens with Single page apps. Then, the new link from the HTML form is collected. Using template find() method form field values are retrieved.Finally, by calling Movies.insert(), the new link is inserted into the Links collection. Notice that we are explicitly inserting the newly added link into the client-side Links collection. Meteor inserts the new link into the server-side Links collection behind the scenes. When Meteor inserts the link into the server-side collection, the new link is added to the MongoDB database associated with the LinksStore app automatically.

If, for any reason, server side insertion is failed, then Meteor will remove the link from the client-side Links collection automatically. This powerful is Meteor's client to server synchronization.

If you open multiple browsers, and add links, then you would notice that all of the links will appear on all of the open browser automatically. You don’t need to refresh individual browsers to update the client-side Links collection. Meteor keeps everything synchronized between the browsers and server for you.

Now, if the app is started with 'meteor' command from LinkStore directory, we will see like following

Meteor App running

Since form controls are not aligned properly, we will add some custom style within the head section

<style type="text/css">    #url {margin-left: 53px}    </style>

Your app is ready now. You can try to add some data now.

Making your app secure

At this point, your app. though up and running, it is insecure. Let's see how so. Open browser console from your favorite browser and then run a command to insert a value. You will find that the app is allowing that.

insecure app

For a production app, this is not a thing you will not want your users are doing. Fortunately, Meteor provides us with provision to make your app secure.

You can do that by issuing the following command

meteor remove insecure

Secure your Metero app

Now if you try to insert some data from browser colsole, you won't be able to do that.

meteor secure app

Access database form mongo shell

Meteor has 'meteor mongo' command with which you can access the database from mongo shell. This is great if you want to do some manipulation directly from command prompt.

access mongo shell

Deploy

After you built your app, it’s time to deploy it to the web. You can do that in two ways. You may use Meteor's free servers, or you may deploy it to any server with NodeJS and MongoDB installed.

You can deploy your app to the free server with following command

meteor deploy yourSitesName.meteor.com
Deploy Meteor

You get a free hostname and you will have app up and running.

You can have a live demo of the app we build at w3r_links.meteor.com

You can also use your own domain name with this option. In that case, you have to point your DNS records to the free server

To Deploy to your own server, you must first need to create the package using the following command

meteor bundle

All the necessary files that will be required to run your app will be bundled. You need to set Node.js and MongoDb dependencies then.

Conclusion

We have just touched the surface. Meteor offers plethora of opportunities and to develop realtime web apps with a single language. There are many awesome features available in this platform. We will explore those in our upcoming tutorials.



Follow us on Facebook and Twitter for latest update.