Javascript Meteor Tutorial

Post navigation

Introduction

Meteor is an open source Javascript framework for creating real-time apps. When I say real-time, that means that the application responds to events immediately, without reloading. AJAX is often used for this purpose, but we don’t even need to use AJAX with Meteor, since many real-time features are built directly into it. MongoDB is also built directly into Meteor. MongoDB is a database system that can manage any data/information used in our applications.

There are some unique and powerful features within Meteor that are very easy to use. We can create a user login system or deploy our app to the web by entering only a single command in the command line. Meteor focuses on making it easier for the developer to add certain types of functionality to their applications. Meteor apps are also cross-platform, which means they work great on both PC and mobile devices. Even if you lack any knowledge of MongoDB, you may still be able to learn Meteor. However, a working knowledge of MongoDB is essential to taking advantage of all the features Meteor has to offer. Outside of that, the only pre-requisites required to learn Meteor are basic skills in HTML, CSS, and Javascript.

Installing Meteor

Installing Meteor is especially easy for Linux and Mac users, as it only involves entering the following command into the terminal:

1

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

If you’re using Windows, you may download the installer from the following link:

Creating Our First App

Now that we’ve installed Meteor, let’s jump right into creating our first application. Open up your terminal and enter the following command to create a new Meteor app named HelloMeteor:

1

meteor create HelloMeteor

After the app is created, enter the following commands to change into our application directory and fire up a development server so that we may run our app:

1

2

cd HelloMeteor

meteor

By default, our Meteor server will use port 3000. Go into a web browser and visit the following location:

localhost:3000

If the above URL did not work, try replacing localhost with 127.0.0.1

Your browser window should look like the screenshot in Figure 3-1:

Figure3-1

Clicking the button increases the value displayed in the string of text below the button. Let’s take a look at the source code of HelloMeteor.html, which may be found in the directory of your HelloMeteor application. Within the HTML, you may notice an element named template that you’ve never seen before. Meteor uses a template engine to render HTML content. Templates are always placed outside of the body tags, as they are separate in a sense from the rest of the HTML. The name of our template is hello, which you see referenced in the body of our HTML. When the output is rendered, the {{> hello}} is replaced by the HTML of our template named hello. Likewise, if we had a template named menu, we could display it in the body of our html with {{> menu}}. As a quick experiment, duplicate the {{> hello}} by copying that line of code and pasting it into a new line immediately after it. When you refresh your browser, the output should look like Figure 3-2:

Figure 3-2

Go ahead and remove the duplicate {{> hello}} now that you understand how the templates work. You may also notice within our template, we reference something named counter (which is surrounded by two sets of curly braces). Although {{> signifies a template, two curly braces without a greater than symbol signify a helper to call from our Javascript. In HelloMeteor.js, we have a session variable named counter that begins at zero. The {{counter}} within our HTML isn’t referencing our session variable directly, it is actually calling the helper function counter defined in Template.hello.helpers (which returns the value of our session variable). In Template.hello.events, we have an event listener for buttons that increments the value of our session variable by one. Last but not least, you’ll notice that all of our code is within a conditional block that runs if Meteor.isClient is true. All of the code that runs on the client goes here, while all the code that runs of the server goes in the block under the conditional test for Meteor.isServer. That’s pretty much all there is to it.

Creating Custom Apps

The default app created by Meteor serves as a great introductory example, but leaves one thirsty for more. Let’s develop a custom app named RestaurantReviews to further explore the features of Meteor. The idea behind the app will be a service for people to read and post restaurant reviews. Create a new app named RestaurantReviews:

1

meteor create RestaurantReviews

For this first version of our app, we will only be using HTML and Javascript; we will add CSS styling later on. Replace the code in RestaurantReviews.html with the code in Code Listing 4-1:

Code Listing 4-1

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

<head>

<title>RestaurantReviews</title>

</head>

<body>

<h1>RestaurantReviews</h1>

{{>restaurantInfo}}

<br/><br/>

{{>addReview}}

{{>restaurantReviews}}

</body>

<template name="restaurantInfo">

<br/>

Restaurant Name:Back Block Pizza

<br/>

Address:123Hello World Road&nbsp;&nbsp;&nbsp;Providence,RI

<br/>

Phone:401-555-5555

<br/><br/>

Description:At Back Block Pizza,making pizza isn'tjust our job;the"Way of the Pizza"istruly an art form tous.We also have hot/cold grinders,crispy chicken wings,andvarious appetizers.

Then, replace the code in RestaurantReviews.js with the code in Code Listing 4-2:

Code Listing 4-2

JavaScript

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

varReviews=newMeteor.Collection("Reviews");

if(Meteor.isClient){

Template.restaurantReviews.helpers({

reviews:function(){

returnReviews.find({},{sort:{time:-1}});

}

});

Template.addReview.events({

'click button':function(){

varuser=document.getElementById('name');

varreview=document.getElementById('review');

varrating=document.getElementById('rating');

if(user.value!=''&&rating.value!=''&&review.value!=''){

Reviews.insert({

user:user.value,

review:review.value,

rating:rating.value,

time:newDate().toString()

});

}

}

});

}

if(Meteor.isServer){

Meteor.startup(function(){

// code to run on server at startup

});

}

In your terminal, launch a development server by entering the meteor command from your application directory (RestaurantReviews). If you visit localhost:3000 in your browser, your browser window should look similar to Figure 4-1:

Figure 4-1

Go ahead and add a few reviews. The reviews should show up as in Figure 4-2:

Figure 4-2

Let’s take a step back and examine the big picture of what’s going on in our code. The body of our RestaurantReviews.html file just references three other templates: restuarantInfo, addReview, and restaurantReviews.

The restaurantInfo template displays information about the restaurant we’re reviewing, and is by far the simplest (it’s nothing but text with line breaks). A real app would be more dynamic, as you would be able to choose different restaurants to review. However, to prevent making the app too confusing, I just used a static placeholder for this template.

The addReview template consists of an input box, a drop down list, a text box, and a submit button. It’s essentially the template that is responsible for collecting user input. In RestaurantReviews.js, we define an event handler for button clicks. Whenever a button is clicked inside the addReview template, we insert the user input into a MongoDB collection named Reviews (as long as none of the input values are empty). For those of you with a more traditional SQL background, a collection is another way of saying a table in our MongoDB database. In other words, all of the reviews are actually just data in a database. The argument to Reviews.insert is a comma separated list of the different fields and their values. We include fields for the user, their review, their rating, and the time at which it was submitted.

The restaurantReviews template displays all of the reviews that have been submitted for a particular restaurant. In our Javascript code, we have a helper function defined for restuarantReviews named reviews. This returns all of the reviews in our Reviews collection by using the find function. Our find function sorts the data based on the time the review was submitted. The -1 value instructs it to sort in descending order (1 would sort in ascending order). This way, the most recent reviews show up at the top. Back in our HTML, we iterate through the collection with {{#each reviews}}, which works similar to how for-each loops work in other languages. Basically, it just goes through each review in the collection, one by one. In every iteration of the loop, we display the user, the time they submitted their review, their rating and any comments they have about the restaurant.

Points for Style

We already have a fully functional app, but we want to create something that actually grabs our user’s attention to draw them in. Since the functionality works the way it needs, we won’t need to make any changes to RestaurantReviews.js. We only need to make some slight changes to RestaurantReviews.html and add some CSS styling to RestaurantReviews.css. Replace RestaurantReviews.html with the code in Code Listing 5-1:

Code Listing 5-1

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

<head>

<title>RestaurantReviews</title>

</head>

<body>

<div class="restaurantDiv">

<h1>RestaurantReviews</h1>

{{>restaurantInfo}}

</div>

<div class="addReviewDiv">

{{>addReview}}

</div>

<div class="reviewDiv">

{{>restaurantReviews}}

</div>

</body>

<template name="restaurantInfo">

<div id="info">

<br/>

Back Block Pizza

<br/>

123Hello World Road

<br/>

Providence,RI

<br/>

401-555-5555

<br/><br/>

At Back Block Pizza,making pizza isn'tjust our job;the"Way of the Pizza"istruly an art form tous.We also have hot/cold grinders,crispy chicken wings,andvarious appetizers.

We won’t go into detail about the CSS involved here, but there is plenty of information about it on the web. Moreover, you don’t really need a strong understanding of CSS to really understand Meteor itself. If you refresh your browser, you will be amazed by how different your app now looks with the CSS styling added to it. We really didn’t change much in the HTML besides add divs, and the Javascript is exactly the same; adding the CSS is the only major change we have made. It should render similar to Figure 5-1 and Figure 5-2:

Figure 5-1

Figure 5-

I left room at the left and right of the content, as they could be used for navigation menus, a search tool (for choosing a restaurant), advertisements, and more. It may look better to stretch our content the entire width on mobile devices.

Adding User Logins

There is one more feature that I want us to add to our app. Meteor makes it incredibly easy to support user accounts and login functionality. You may even configure it to use their email, a chosen username, their Facebook account, and more using minimal coding. Not only that, we may want to require users to be logged in before they post a review. Let’s go ahead and add some of that functionality. Enter the following command into your terminal (while in the directory of your application) to add the packages for the accounts user interface:

1

meteor add accounts-ui accounts-password

There are only minimal changes that we need to make in RestaurantReviews.html. First, change the input box for the person’s name into a label that contains the loginButtons template (it’s a default template from the accounts package):

<label id=”login”>{{> loginButtons }}</label>

Then, only show the rest of the addReview template if the person is logged into the system. We do this by checking the value of currentUser (currentUser returns true if you’re logged in, otherwise false):

{{#if currentUser}}
// Code to execute here
{{/if}}

Finally, we need to change “Name: “ to “User: “ in the label that lists the user that placed the review (since we now are using usernames instead of people’s names to identify them). The code of RestaurantReviews.html should now be similar to Code Listing 6-1:

Code Listing 6-1

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

<head>

<title>RestaurantReviews</title>

</head>

<body>

<div class="restaurantDiv">

<h1>RestaurantReviews</h1>

{{>restaurantInfo}}

</div>

<div class="addReviewDiv">

{{>addReview}}

</div>

<div class="reviewDiv">

{{>restaurantReviews}}

</div>

</body>

<template name="restaurantInfo">

<div id="info">

<br/>

Back Block Pizza

<br/>

123Hello World Road

<br/>

Providence,RI

<br/>

401-555-5555

<br/><br/>

At Back Block Pizza,making pizza isn'tjust our job;the"Way of the Pizza"istruly an art form tous.We also have hot/cold grinders,crispy chicken wings,andvarious appetizers.

The only thing that we will be adding to our CSS is code to style our login buttons:

CSS

1

2

3

4

5

6

7

8

#login {

margin:0px;

height:25px;

vertical-align:center;

width:40%;

float:left;

background:#DF9000;

}

We also need to remove float: left; from the CSS styling for the input element (otherwise the sign-in button will overlap some of the accounts UI).

We will need to make a few different changes to RestaurantReviews.js. First, remove the code that initializes and stores our variable user (var user = getElementById(‘name’);). Next, change the if statement so that it no longer checks if the value of user is empty (we just removed the user variable). In our insert statement, change the value of the user field to store Meteor.user().username (which returns the username of the currently logged in user) instead of user.value. Also, add the following to the bottom of your client code so that your login system works with usernames instead of emails (it uses email by default):

CSS

1

2

3

Accounts.ui.config({

passwordSignupFields:"USERNAME_ONLY"

});

Refresh your app, and you should now have login functionality as in Figure 6-1 and Figure 6-2:

Figure 6-1

Figure 6-2

Click on the Sign In button, create an account, login to your account, post a review, and log out.

One useful final note – executing Reviews.remove({}); from within your Javascript code will remove all of the rows of your database. Be careful with this command. However, you will end up with a lot of junk data if you modify the code and keep testing it by adding reviews. Sometimes it is helpful to clean up this junk data.

Deploying Our App

Deploying our app to the web is a piece of cake in Meteor. You may run it off of your own server, although for the purposes of this tutorial, we will be using Meteor’s server. In a terminal, go to the directory of your app (RestaurantReviews) and execute the following command:

1

meteor deploy AppName.meteor.com

Replace AppName with whatever you would like to call it, and your app will be hosted there. Visit it in a browser and even share it with your friends. Now that it’s on the internet, it may be viewed by anybody anywhere (with an internet connection, of course). In my case, I chose to deploy my app to restaurantreviews.meteor.com which you may visit in a browser.

Now that we have built a custom app from start to finish in Meteor, think of ideas of simple apps that you could create with it. The best way to learn programming is to jump right in and do it. Keep learning and never stop having fun.