Search icon CANCEL
Subscription
0
Cart icon
Your Cart (0 item)
Close icon
You have no products in your basket yet
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Conferences
Free Learning
Arrow right icon
Mastering MeteorJS Application Development
Mastering MeteorJS Application Development

Mastering MeteorJS Application Development: MeteorJS makes full-stack JavaScript Application Development simple – Learn how to build better modern web apps with MeteorJS, and become an expert in the innovative JavaScript framework

Arrow left icon
Profile Icon Jebin BV Profile Icon Arturas Lebedevas
Arrow right icon
$48.99
Full star icon Full star icon Full star icon Full star icon Empty star icon 4 (5 Ratings)
Paperback Dec 2015 298 pages 1st Edition
eBook
$9.99 $39.99
Paperback
$48.99
Subscription
Free Trial
Renews at $19.99p/m
Arrow left icon
Profile Icon Jebin BV Profile Icon Arturas Lebedevas
Arrow right icon
$48.99
Full star icon Full star icon Full star icon Full star icon Empty star icon 4 (5 Ratings)
Paperback Dec 2015 298 pages 1st Edition
eBook
$9.99 $39.99
Paperback
$48.99
Subscription
Free Trial
Renews at $19.99p/m
eBook
$9.99 $39.99
Paperback
$48.99
Subscription
Free Trial
Renews at $19.99p/m

What do you get with Print?

Product feature icon Instant access to your digital eBook copy whilst your Print order is Shipped
Product feature icon Paperback book shipped to your preferred address
Product feature icon Download this book in EPUB and PDF formats
Product feature icon Access this title in our online reader with advanced features
Product feature icon DRM FREE - Read whenever, wherever and however you want
OR
Modal Close icon
Payment Processing...
tick Completed

Shipping Address

Billing Address

Shipping Methods
Table of content icon View table of contents Preview book icon Preview Book

Mastering MeteorJS Application Development

Chapter 1. Building a MeteorJS Web Application

The need for omni-presence has increased dramatically and the Web is the primary means of being really omni-present. This has led to tremendous advancements in the technology that subsequently gave us a window to the ever-growing Web, which is browsers. To develop something interactive in the browser, we end up with the ultimate language, JavaScript. Though it is the most underestimated and misinterpreted language, it has gained enormous value in the last decade. The rise of libraries and frameworks, such as jQuery, YUI, Backbone.js, Angular.js, Ember.js, and so on, have transformed the way applications are developed today. It didn't stop there, and the language found its space in the server as well, with the introduction of Node.js. Now, the language also manages to find a warm welcome in IoT space, with the introduction of Tessel.io, Windows 10, and so on. This is a better time than ever to become a JavaScript developer.

There is a trend where backend, that is, the data access layer, is developed with other languages, while the whole app is rendered and managed using one of the MV* JavaScript frameworks in the browser itself. With Node.js, JavaScript applications started becoming isomorphic. Node.js is very popular because of the default asynchronous behavior. Frameworks such as Express.js helped to create isomorphic applications.

Still something was missing. Even after all these improvements, we developed applications with a lot of redundancies in terms of code. For example, data fetching, data binding, view to model reactivity, and so on, are not really that efficient. So, a group of developers gathered around and found a powerful solution called MeteorJS. This book is about mastering your skill to develop applications using MeteorJS.

In this chapter, we will learn the following parts of MeteorJS by developing an application:

  • MeteorJS internals and working principles
  • How to build a customized login solution
  • How to create routes, templates, and layouts
  • Handling forms from the template handlers
  • Persisting the data to a database
  • Data handling between the client and server and reactive variables
  • How to use multiple layouts in the application

An overview of MeteorJS

As I have mentioned earlier, MeteorJS is an open source isomorphic framework that is built using JavaScript that runs on Node.js. The beauty of the framework lies in the core principles of the framework. A truly modern application needs to be highly reactive. To be reactive, the existing stack is not that great. HTTP is slow because of the latency in handshaking on every request. The databases that we use are not reactive. HTML needs to be updated as and when the data changes, which is an overhead for developers. Also, the updated data must be transferred to all the clients without a refresh or manual intervention. MeteorJS provides a one-stop solution for all these problems and needs.

To master something, it is not enough to know how to use it, but also it is absolutely necessary to know the internal working of the thing. In our case, it is really important to know the working principles of MeteorJS to master it.

MeteorJS is built using a bunch of packages that can be used independently in one of your projects if needed. Let's take a deeper look into these packages.

A typical MeteorJS application has three parts: the server, the communication channel, and the client. Once a server is connected to a client, there is a socket introduced between the client and the server. Any data transfer that happens between the server and the client is through this socket.

Server

The server is where MeteorJS is installed on top of Node.js. MeteorJS, on the server, is connected to MongoDB that is the default database for the framework.

MongoDB

MongoDB is a NoSQL database. Each record is a document and the set of documents is called a collection that is equivalent to a table in a SQL database. As you may know, MongoDB is an in-memory JSON-based database, which means it is extremely fast in favorable conditions. Usually, MongoDB can have operation logs, which is called oplog. The oplog has the database operations happening with time. This is used in the case of making the replica (slave) of the primary database. The operations that happen in the primary database are copied to the secondary databases asynchronously.

Though MongoDB is not a reactive database, Livequery, which is a part of MeteorJS, does some work internally to get the updates of the database periodically. Livequery can connect to the database and set triggers on certain conditions as required. In the case of MongoDB, triggers are not supported. So, the Livequery depends on oplog if enabled, or else it will poll the database at a particular interval. When oplog is enabled, which should be the case for production, MeteorJS observes the oplog and intelligently does the transaction. If oplog is not enabled, meteor polls the database, computes the diff, and then sends the changed data to a client. Livequery can guess when to poll the database as all the write operation to the database go via Livequery.

Publish/Subscribe

A very important part of MeteorJS is this good old design pattern. By default, the entire Mongo database is published to the client from the server. However, it is not good for production to auto-publish all the data to the client. Instead, the client can subscribe to the required data that is published by the server. The subscriber will automatically be updated whenever there is a change in the subscribed data:

/* Publishing from server. */
if (Meteor.isServer) {
  Meteor.publish("tasks", function () { //Registering "tasks" publication
    return Tasks.find();
  });
}
/* Subscribing from client */
Meteor.subscribe("tasks");

Communication channel

In the realm of publish and subscribe, there should be a way to transfer the subscribed data. MeteorJS uses a protocol called Distributed Data Protocol (DDP). To define DDP, it is simply a REST over Web socket. It is a socket implementation that can transfer JSON data to and fro (duplex). MeteorJS uses Socket.io internally to establish a socket connection between the client and the server. However, neither the client nor the server knows to whom they are talking to. All they know is to talk DDP over the socket.

DDP is human-readable and one can literally see what is transferred via DDP using the package Meteor DDP analyzer. Over DDP, there will be either a message transfer or procedure calls. You can use DDP not only with MeteorJS, but also with any other languages or projects that can support socket. It is a common standard protocol that gives a great way to pair with any other DDP-consuming implementation, if required. Sockets reduce latency in a very high rate than HTTP, because of which it is very much suitable for reactive applications.

Client

Let's say the server is ready with the data. How does the client keep all this data so that it can be reactive? Also, who is doing the magic of refreshing the views when the data changes?

Modern apps try their best to solve two things as intelligently as possible. One is latency compensation and another is reactivity. MeteorJS does that quiet powerfully using the following implementations.

MiniMongo

Being a developer, if you are implementing a table that can be sorted, filtered, and paginated, what will you do to make it faster? Won't you fetch the data and keep it in browser memory in the form of multi-dimensional array, apply all the operations on the cached array, and update the table as and when required? The same is the case for MeteorJS with little advancement in the cache implementation. Instead of using a plain object or array, MeteorJS creates a cache in the browser called MiniMongo, which is again a simplified client memory database. The highlight is that you can query it in the way you query the MongoDB that enables you to use the same query both in the client and the server.

Whenever there is change in MongoDB, the server sends the difference to the client and that data is stored in MiniMongo. At any instance, MeteorJS tries to keep both the MongoDB in sync.

Tracker

Now, the data is with the client. Let's call this model. In a MV* framework, we have the views bound to models to auto-update the views as the model changes. In Backbone.js, you have to do it explicitly. However, in Angular.js, it is taken care of by the framework itself with the help of $ scope and digest cycles. How does MeteorJS handle data changes? With the help of Trackers. Trackers create observers for everything you need to track. By default, MeteorJS has enabled a tracker on certain data sources, such as database cursors and session variables. You can even have a custom variable to be tracked using the tracker.

Blaze

Blaze is a templating engine that is reactive because of the tracker. Blaze plays the magical part of reactivity by binding the data to the templates. An important point to note is that Blaze is declarative, which means you just have to tell Blaze what to do when the data changes, and need not say how to do it. With the help of the tracker, Blaze keeps a track of model changes and reacts to the change. The default templates are spacebars. This is a variant of Handlebar's templating engine. You can use Jade as well. Blaze is again intelligent to compute the diff of what needs to be updated. It doesn't update all the template until it is necessary. Blaze handles the user interactions and thereby makes a call to the server, if absolutely needed.

Additional information

Developers can use MeteorJS ecosystem, which has a lot of packages to use in the application. Iron router, masonry, auto-form, simple schema, and twitter bootstrap are a few important packages for application development. Being a Node.js-based framework, developers can harness the power of Node.js ecosystem as well. You can also use NPM packages in the MeteorJS application.

MeteorJS does hot code deployment, which means without restarting the application, the code is deployed and the client will see the changes without completely refreshing the browser.

Note

MeteorJS has just reached 1.x. There are many new features and implementations yet to come such as drivers for different databases, support of various front-end frameworks, and so on. However, basically, MeteorJS is designed in a way to accommodate anything just by small integration work. If you really want to see if this is true, check their source in GitHub (https://github.com/meteor/meteor/tree/devel).

It was said, "To know the truth, return to the source".

If you are interested in learning more about the framework's internals, I would suggest take a look at the source code that will help you learn a lot of new things.

Developing a bus reservation application

Long story, short—MeteorJS is awesome. Let's take a look at the awesomeness of MeteorJS by developing an application.

By developing this application, you will learn about MeteorJS login, routing, using multiple layouts based on route, form handling, database operations, publishing and subscribing data, custom reactive data sources, and server calls. By the end, you will see the reactivity of the framework in action.

To understand and experience MeteorJS, we are going to build a bus reservation application. Let's define what we are going to develop and then get our hands dirty:

  • Develop and enable account creation and login
  • Create bus services
  • Create a landing page that has the list of buses available
  • Develop a search section besides the listing so that the users can reach their appropriate bus for booking
  • Create a reservation page where users can block and reserve the seats

To keep the application simple, a lot of details are omitted. You can implement them on your own later.

Note

This is not the professional way to build MeteorJS. With this application, you will get started and in the upcoming chapters, you will learn how to develop apps like a pro.

Basic prerequisite is that Meteor must be installed. You should know how to create an application and add or remove packages, and also know a little about routes, mongo, and collections.

Let's start from scratch. Create a MeteorJS application using the create command (meteor create BookMyTravel) and remove all the default .html, .css, and .js files. Create the following directories: assets, client, commons, and server. Remove the insecure (meteor remove insecure) and autopublish (meteor remove autopublish) packages. Add the twitter bootstrap (meteor add twbs:bootstrap) package that will help us with layout and designing. Add the Moment.js (meteor add momentjs:moment) package for data manipulation.

As our application is not a single page application, routes are required to navigate between pages. For routing purposes, we'll use the famous iron-router package. Add the iron-meteor package to the application by running the meteor add iron:router command. Create the routes.js file inside the commons directory and add the following code:

Router.configure({
  notFoundTemplate: 'notFound',   //template with name notFound
  loadingTemplate: 'loading'      //template with name loading
});
Router.onBeforeAction('loading');  //before every action call show loading template

Define these two templates in an HTML file of your choice as follows:

<template name="notFound">
  <div class="center">You are lost</div>
</template>
<template name="loading">
  Loading...
</template>

Here, we specify the global loading template and the page-not-found template. If you only have one layout template for the entire application, you can add it here. This configuration is optional and you can create those templates as per your need. If you configure these options, it is mandatory to create these templates. This configuration will act as a global configuration. For more details, take a look at the iron-router package documentation (https://github.com/iron-meteor/iron-router).

Since our application is going to be route-driven, which is a common trait of large non-singe-page-applications, we have to define routes for each navigation. This iron-router exposes the Router object into which we have to define (map) your routes.

In each route, you can provide path as the first parameter that is the actual route, an object as the second parameter that can have name that is useful for named navigations, template that is the actual view, layoutTemplate that is optional and is a container for the template mentioned earlier, and yieldTemplates that allows you to render multiple templates into the layout specified. There are still a lot of other options we can configure. However, these are the predominant ones. The example for this is as follows:

//path is / which is the landing page
Router.route("/", {
  //name is "home"
  name: "home",
  //on route / the layout template will be the template named "homeLayout"
  layoutTemplate: "homeLayout",
  //on route / template named "home" will be rendered
  template: "home",
  //render template travelSearch to search section of the layout template.
  yieldRegions: {
    travelSearch: {to: "search"}
  }
});

Our application will use multiple layouts based on the routes. We will use two different layouts for our application. The first layout (homeLayout) is for the landing page, which is a two-column layout. The second layout (createTravelLayout) is for travel (bus service) creation and for the reservation page, which is a single-column layout. Also, define the loading and the notFound templates if you had configured them.

Accounts

I am not going to explain much about account (signin/signup). MeteorJS comes, by default, with accounts and the accounts-ui package that gives us instant actionable login templates. Also, they provide third-party login services such as Google, Facebook, Twitter, GitHub, and so on. All of these can be made available just by configurations and less amount of code.

Still, they do not suffice for all of our needs. Clients might need custom fields such as the first name, gender, age, and so on. If you don't find the accounts-ui package to serve your purpose, write your own. MeteorJS provides extensive APIs to make logging in smooth enough. All you need to do is understand the flow of events. Let us list down the flow of events and actions for implementing a custom login.

Signup

Create your own route and render the sign up form with all the desired fields. In the event handler of the template, validate the inputs and call Account.createUser (http://docs.meteor.com/#/full/accounts_createuser) with the e-mail ID and password. The additional user information can go into the profile object. Also, if required, you can change the profile information in the Account.onCreateUser callback. You can use Accounts.config (http://docs.meteor.com/#/full/ accounts_config) to set certain parameters such as sending e-mail verification, setting restrictions to account creation (unconditionally or conditionally), login expiration, and secret keys. Obviously, we need to send a verification link to the user by e-mail on signup. Add the e-mail package to the application and provide the SMTP details at the server-side (http://docs.meteor.com/#/full/email") as follows:

Meteor.startup(function () {
  smtp = {
    username: '',   // eg: bvjebin@meteorapp.com
    password: '',   // eg: adfdouafs343asd123
    server:   '',  // eg: mail.gmail.com
    port: <your port>
  }
  process.env.MAIL_URL = 'smtp://' + encodeURIComponent(smtp.username) + ':' + encodeURIComponent(smtp.password) + '@' + encodeURIComponent(smtp.server) + ':' + smtp.port;
});

If you are using the default e-mail verification, which is good to use, you can customize the e-mail templates by adding the following code to the server that is self-explanatory:

Meteor.startup(function() {
  Accounts.emailTemplates.from = 'Email Support <support@bookMyTravel.com>';
  Accounts.emailTemplates.siteName = 'Book My Travel';
  Accounts.emailTemplates.verifyEmail.subject = function(user) {
    return 'Confirm Your Email Address';
  };
  /** Note: if you need to return HTML instead, use .html instead of .text **/
  Accounts.emailTemplates.verifyEmail.text = function(user, url) {
    return 'click on the following link to verify your email address: ' + url;
  };
});

When the verification link is visited by the user, callbacks registered with the Accounts.onEmailVerificationLink method will be called. If you want to prevent auto-login, call the Account.createUser method in a server rather than in a client. The Accounts.validateNewUser method can be used to register callbacks, which will validate the user information. Throwing an error from this callback will stop user creation.

Signin

The Meteor.loginWithPassword method (http://docs.meteor.com/#/full/meteor_loginwithpassword) needs to be called if you have a custom login form. There are helpers such as Accounts.validateLoginAttempt, Accounts.onLogin, and Accounts.onLoginFailure to perform various actions in the middle via callbacks, if needed. Once logged in, Meteor.user() and Meteor.userId will have the user information. To check whether the user is logged in or not, you can use if(Meteor.userId). In the Account.onLogin method, we can register a callback that will navigate to a desired route on successful login.

The accounts package also provide various methods such as changePassword, forgotPassword, sendResetPasswordEmail, resetPassword, setPassword, and onResetPasswordLink that completes the accounts implementation. One can make use of these methods to customize the login as required.

I hope all these details help you in creating a custom account management module.

Creating a bus service

Though this section is not going to be our landing page, we will develop the bus service creation part first, which will give us enough data to play around the listing section.

While developing a server-based application, we can start with routes, then the models, followed by the interfaces, and, lastly, the server calls. Thinking in this order will give us a fair idea to reach our goal.

Let's define a route. The route name is going to be createTravel. The URI or path is /create-travel, the layout can be createTravelLayout and the template can be createTravel. The route will look like the following code snippet; copy it to routes.js.Router.route:

("/create-travel", {
  name: "createTravel",
  layoutTemplate: "createTravelLayout",
  template: "createTravel"
});

Now, we need to define our collections. In the first place, we need a collection to persist our travel service (bus services).

Create a file, collections.js, in the commons directory so that we can access this collection both in the server and client. This is a big advantage of isomorphic applications. You don't have to define collections in two places. Place the following snippet in the collections.js file:

BusServices = new Meteor.Collection("busservice");

Mind the global variable BusServices that has to be global so that it can be accessed across the application. Using a global variable is bad practice. Still, we have to live with it in the case of MeteorJS. Where it is avoidable, avoid it.

MeteorJS will create the busservice collection in the database on the first insertion. We get a handle to this collection using the BusServices variable. It's time to decide all the fields we need to persist in the collection. We will have _id (auto-generated by MeteorJS), name, agency, available_seats, seats, source, destination, startDateTime, endDateTime, fare, createdAt, and updatedAt.

You can add whatever you feel that should be present. This part helps us to create the UI to get the user inputs. Let's create a form where the user inputs all these details.

As mentioned in the route, we need a layout template and a view template to display the form in the client. Create a directory with the name createTravel in the client directory and add a layout file createTravelLayout.html. Our layout will be as follows:

  <!-- name attribute is the identifier by which templates are identified -->
<template name="createTravelLayout">
  <div class="create-container">
    <header class="header">
      <h1>{{#linkTo route="home"}}BookMyTravel{{/linkTo}}</h1>
      <ul class="nav nav-pills">
        <li>{{#linkTo route="home"}}List{{/linkTo}}</li>
      </ul>
    </header>
    <section class="create-container__section">
      {{> yield}}
    </section>
    <footer class="footer">Copyright @Packt</footer>
  </div>
</template>

One important code in the template is {{> yield}}. This is a built-in helper/placeholder where the actual view template will be placed, which means the createTravel template will be placed in {{> yield}} as a part of this layout.

Create the view template file, createTravel.html, in the same directory as the layout and paste the following code:

<template name="createTravel">
  <div class="row col-md-6 col-md-offset-3 top-space">
        <div class="col-md-12 well well-sm">
            <form action="#" method="post" class="form" id="signup-form" role="form">
              <div class="error"></div>
              <input class="form-control" name="name"type="text" required />
           <input class="form-control" name="agency"required />
           <input class="form-control" name="seats"type="number" required />
             <div class="row">
                <div class="col-xs-6 col-md-6"><input class="form- control" name="startpoint"type="text" required /></div>
                  <div class="col-md-6"><input class="form- control" name="endpoint" type="text" required /></div>
              </div>
             <div class="row">
                <div class="col-md-3"><input class="form-control" name="startdate" type="date" required /></div>
      <div class="col-md-3"><input class="form-control" name="starttime" type="time" required /></div>
      <div class="col-md-3"> <input class="form-control" name="enddate" type="date" required /></div>
      <div class="col-md-3"><input class="form-control" name="endtime" type="time" required /></div>
              </div>
              <input class="form-control" name="fare" type="number" required />
              <button class="btn btn-lg btn-primary btn-block" type="submit">Create</button>
            </form>
        </div>
    </div>
</template>

We are almost there. We need to see how this looks. Start the meteor server using the meteor or meteor -p <port number 3001> command. Navigate to localhost:3000/create-travel in your browser.

You will see the form, but the layout is broken. Some styles are needed. Create a file, styles.css, in assets directory and add the following styles to it. I am using a flex box for the layout, along with a twitter bootstrap:

body { height: 100vh; display: flex;}
.header, .footer {
  flex: 0 1 auto;
  height: 60px;
  border-top: 1px solid #ccc;
  background: #ddd;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 20px;
}
.header {border-bottom: 1px solid #aaa;}
.header h1 { margin: 0; }
.footer {height: 40px; text-align: center; justify-content: center;}
.home-container, .create-container {width: 100%;display: flex;flex-direction: column;}
.home-container__section, .create-container__section {display: flex;flex: 1 1 auto;overflow: auto;}
.home-container__section__left {flex: 1 1 auto;box-shadow: inset 0px 0px 4px 1px #ccc;}
.main {overflow: auto;}
.bus-list {margin: auto;}
.bus-list__header {background-color: #ddd;height: 45px;}
.bus-list__row {border-bottom: 1px solid #ccc;height: 50px;}
.bus-list__row-empty {padding: 20px;}
.bus-list__row__col {text-align: center;border-right: 1px solid #fff;height: 100%;display: flex;justify-content: center;align-items: center;
}
.bus-list__row__col.last {border: 0;}
.bus-list__body {background-color: #efefef;}
.accounts-container__row {  margin-top: 7em; }
.busView {display: flex;flex-direction: column;padding: 20px 0;}
.busView__title {flex: 0 1 auto;height: 50px;}
.busView__seats {margin: 0 auto;}
.busView__left, .busView__right {border: 1px solid #ccc;}
.busView__book {padding-top: 2em;}
.busView__seat {text-align: center;vertical-align: middle;height: 25px;width: 25px;border: 1px solid #ccc;margin: 13px;cursor: pointer;display: inline-block;}
.busView__seat.blocked {background-color: green;}
.busView__seat.reserved {background-color: red;}
.busView__divider {display: inline-block;}
.busView__divider:last-child {display: none;}
.top-space {margin-top: 5em;}
.error {color: red;padding-bottom: 10px;}
.clear {clear: both;}
.form-control { margin-bottom: 10px; }

This has all the necessary styles for the whole application. Visit the page in the browser and you will see the form with styles applied and layout fixed, as shown in the following image. MeteorJS refreshes the browser automatically when it detects a change in the files:

Creating a bus service

The last part of the create section is persistence. We have to collect the input on submit, validate it, and call the server to persist it. We should try to avoid direct database insertions from the client.

To collect data from the client, we will create a helper file, createTravel.js, in the createTravel directory and add the following code to it:

Template.createTravel.events({
  "submit form": function (event) {
    event.preventDefault();
    //creating one object with all the properties set from user input
    var busService = {
      name: event.target.name.value,
      agency: event.target.agency.value,
      seats: parseInt(event.target.seats.value, 10),
      source: event.target.startpoint.value,
      destination: event.target.endpoint.value,
      startDateTime: new Date(event .target.startdate.value+" "+event.target.starttime.value),
      endDateTime: new Date(event .target.enddate.value+" "+event.target.endtime.value),
      fare: event.target.fare.value
    };
    //Checking if start time is greater than end time and throwing exception
    if(busService.startDateTime.getTime() > busService.endDateTime.getTime()) {
      $(event.target).find(".error").html("Start time is greater than end time");
      return false;
    }
    //Server call to persist the data. 
    Meteor.call("createBusService", busService, function(error, result) {
      if(error) {
        $(event.target).find(".error").html(error.reason);
      } else {
        Router.go("home");
      }
    });
  }
});

Tip

Downloading the example code

You can download the example code files from your account at http://www.packtpub.com for all the Packt Publishing books you have purchased. If you purchased this book elsewhere, you can visit http://www.packtpub.com/support and register to have the files e-mailed directly to you.

MeteorJS provides the Template global variable that holds the template objects in the page. So far, we have two templates, the createTravel and createTravelLayout templates. One can add events and helpers to these templates using these objects. If you look at the preceding code snippet, we are attaching a submit handler to the form we created. One can refer any template using the name of the templates. Everything else is pretty straightforward. By default, jQuery is available inside the template helpers, and if you wish, you can use it for DOM data retrieval.

In the submit handler, all we do is, collect the filled form data and pack it in an object. You can validate if you need it right here. There is a validation which checks for the start time to be greater than the end time and stops proceeding to call the server. The rest of the fields are validated by HTML5 form attributes.

The important part of the preceding code snippet is the last few lines, which is the call to the server. Now is the time to create the server handler.

Create a file, createTravel.js, in the server directory and add the following code snippet to the file:

Meteor.methods({
  createBusService: function(busService) {
    if(!busService.name) {
      throw new Meteor.Error("Name cannot be empty");
    }
    if(!busService.agency) {
      throw new Meteor.Error("Agency cannot be empty");
    }
    if(!busService.seats) {
       throw new Meteor.Error("Seats cannot be empty");
    }
    busService.createdAt = new Date();
    busService.updatedAt = null;
    busService.available_seats = parseInt(busService.seats, 10);
    BusServices.insert(busService);
  }
});

We have created a server method called createBusService, which takes the busService object, does some validation, and then adds createdAt, updatedAt and available_seats. Finally, it inserts the objects to the database. The BusServices object is the collection variable we created sometime back, if you remember.

It is always good to do the validation at the server end as well. This is because, at the developer front, it is always said, not to trust the client. They can modify a client-side validation easily and make the client post the irrelevant data. As developers, we have to do all the necessary validations at the server end.

This server method is called from the client in the submit handler using Meteor.call with three arguments: the server method name, parameters to the server, and callback.

The callback is called with two parameters: error and result. If there is an error, result is undefined; if the result is present, the error is undefined. One can do post actions based on these parameters inside the callback; for example, in our case, we navigate to the home route if all went well, or else we show the error to the user at the top of the form.

Try filling the form now and check whether everything is fine. If the form data is inserted to the database, you will be taken to localhost:3000/. Here, if you have configured notFoundTemplate in the router, it will be rendered. If not, you will see the exception:

Oops, looks like there's no route on the client or the server for url: "http://localhost:3000/".

The reason for this is that we haven't yet defined or mapped the / route to any template so far. How to verify that the data is saved to the database?

Go to your project terminal and run the meteor mongo command. This will log you into the mongo database console. Run the db.busservice.find().pretty() query. This will show all the inserted data in the mongo console.

List and search

In this section of the application, we will show the list of buses available with their details and also we are going to have a reactive search for the list.

Let's start with a route for the list. Add the following to the routes.js file in the commons directory after the createTravel route, which we created earlier:

  Router.route("/", {
  name: "home",
  layoutTemplate: "homeLayout",
  template: "home",
  yieldRegions: {
    travelSearch: {to: "search"}
  }
});

This is the home route. When you hit localhost:3000/, you know what will happen. Pretty much easy to remember, right?

Under the client directory, create a subdirectory called home. The directory name has nothing to do with the route. This directory will have the files to display the list of bus services. Let's create homeLayout.html, home.html, and homeHelper.js.

In homeLayout.html file, add the following code:

<template name="homeLayout">
  <div class="home-container">
    <header class="header">
      <h1>{{#linkTo route="home"}}Booking{{/linkTo}}</h1>
      <ul class="nav nav-pills">
        <li>
          {{#linkTo route="createTravel"}}Create{{/linkTo}}
        </li>
      </ul>
    </header>
    <section class="home-container__section">
      <div class="home-container__section__left container-fluid">
        {{> yield region="search"}}
        </div>
        <div class="main">
          {{> yield}}
        </div>
    </section>
    <footer class="footer">Copyright @Booking</footer>
  </div>
</template>

In home.html file, add the following two templates (list and search):

<template name="home">
  <div class="container bus-list">
    <div class="row bus-list__row bus-list__header">
      <div class="bus-list__row__col col-md-3">Bus</div>
      <div class="bus-list__row__col col-md-1">Available seats</div>
      <div class="bus-list__row__col col-md-1">Start point</div>
      <div class="bus-list__row__col col-md-1">End point</div>
      <div class="bus-list__row__col col-md-2">Start time</div>
      <div class="bus-list__row__col col-md-2">Reaching time</div>
      <div class="bus-list__row__col col-md-1">Fare</div>
      <div class="bus-list__row__col last col-md-1">Book</div>
    </div>
    <div class="row bus-list__body">
    {{#if hasItem}}
      {{#each list}}
      <div class="bus-list__row">
      <div class="bus-list__row__col col-md-3">{{name}}<br />{{agency}}</div>
      <div class="bus-list__row__col col-md- 1">{{available_seats}}/{{seats}}</div>
      <div class="bus-list__row__col col-md-1">{{source}}</div>
      <div class="bus-list__row__col col-md- 1">{{destination}}</div>
      <div class="bus-list__row__col col-md-2">{{humanReadableDate startDateTime}}</div>
      <div class="bus-list__row__col col-md-2">{{humanReadableDate endDateTime}}</div>
      <div class="bus-list__row__col col-md-1">{{fare}}</div>
      <div class="bus-list__row__col last col-md-1"><a href="/book/{{_id}}">Book</a></div>
      </div>
      <div class="clear"></div>
       {{/each}}
    {{else}}
      <div class="row bus-list__row bus-list__row-empty">
      <div class="bus-list__row__col last col-md-12 text-center">No buses found</div>
      </div>
    {{/if}}
    </div>
  </div>
</template>
<template name="travelSearch">
  <div class="col-xs-12 col-sm-12 col-md-12 text-center top-space well well-sm">
  Search
  </div>
  <div class="col-xs-12 col-sm-12 col-md-12 well well-sm">
      <div class="form" id="signup-form">
      <div class="error"></div>
      <input class="form-control" name="startpoint" placeholder="Source(starting from)" type="text" required="">
      <input class="form-control" name="endpoint" placeholder="Destination" type="text" required="">
      <input class="form-control" name="startdate" placeholder="Date" type="date" required="">
      <input class="form-control" name="fare" placeholder="Max prize" type="number" required="">
      </div>
  </div>
</template>

The last thing to add is the helper file. Create homeHelper.js and add the following code:

Template.home.helpers({
  list: function() {
    return BusServices.find();
  },
  hasItem: function() {
    return BusServices.find().count();
  },
  humanReadableDate: function (date) {
    var m = moment(date);
    return m.format("MMM,DD YYYY HH:mm");
  }
});

Previously, we have attached events using the Template object. Now, we have helpers with which you can pass the customized data to the template. Visit the browser and you will find the empty list and the search form.

Wait, we have data in our database. Why didn't it show up in the list? Here comes the data access pattern that we should follow. By default, MeteorJS doesn't send the data to the client when there is no autopublish package. This is a good thing too. When we create a large application, we might not need to send all the database data to the client. The client will be interested in only a few, so let's play with that few.

MeteorJS provides the publish and subscribe methods to publish the required data from a server and subscribes those publications from a client. Let us use these methods to get the data.

In createTravel.js file at the server directory, add the following code:

Meteor.publish("BusServices", function () {
    return BusServices.find({}, {sort: {createdAt: -1}});
});

With this piece of code, the server publishes the busservices collection sorted by the createdAt date with the BusServices identifier.

In the client, to subscribe this publication, add the following line at the top of the homeHelper.js file:

Meteor.subscribe("BusServices");

After this addition, you will see that the list has the trips that you created earlier, as shown in the following screenshot. Now, go create some more travels that we will use for search:

List and search

Also, add the following event handler to homeHelper.js file:

Template.travelSearch.events({
  "keyup input": _.debounce(function(e) {
    var source = $("[name='startpoint']").val().trim(),
      destination = $("[name='endpoint']").val().trim(),
      date = $("[name='startdate']").val().trim(),
      fare = $("[name='fare']").val().trim(),
      search = {};
    if(source) search.source = {$regex: new RegExp(source), $options: "i"};
    if(destination) search.destination = {$regex: new RegExp(destination), $options: "i"};
    if(date) {
      var userDate = new Date(date);
      search.startDateTime = {
        $gte: userDate,
          $lte: new Date(moment(userDate).add(1, "day").unix()*1000)
      }
    }
    if(fare) search.fare = {$lte: fare};
    BusServices.find(search, {sort: {createdAt: -1}});
  }, 200)
});

This is a text box event handler that is debounced by 200 ms for improving performance. The handler collects the search field's data and accumulates it into an object and queries the collection. Do you see any change in the list when you search? It won't, and that is where we get things wrong. Although we have subscribed the busservice collection, MiniMongo holds the data from the server. From one template, when you query the collection, the result doesn't update an other template. We are not changing the subscription itself, instead just the local query. Then, how do we make things happen?

MeteorJS has some data sources that are reactive, by default. For example, database cursors and session variables. However, we need more, don't we? We need custom variables to be reactive so that we can also do the magic. MeteorJS' core team developers have thought about it and provided us with a simple package called reactive-var.

Add the reactive-var package to the application using the meteor add reactive-var command. The logic behind reactive variables is simple—when the value changes, all the instances including the templates will get them immediately.

Simple example of reactive variables is as follows:

var reactVar = new ReactiveVar(2); //2 is default value that can be set in the constructor parameter.
reactVar.set(4); //will update the value of all instance where the reactVar variable is used.

Let's use it in our application. In homeHelper.js, add the following code snippet before the Template.home.helpers method:

var busServicesList = new ReactiveVar([]);
Template.home.onCreated(function() {
  busServicesList.set(BusServices.find({}));
});

This initializes the reactive variable busServicesList with an empty array and then sets the complete busservices collection when the home template' onCreated callback is called. We will use this reactive variable in the templates, instead of the actual collection query cursor. Change the list method in the template helpers to the following:

list: function() {
  return busServicesList.get();
},
hasItem: function() {
  return busServicesList.get().count();
},

Whenever there is a search, we have to update this reactive variable, which will instantly update the template. It is that simple.

Go to the events handler of the search template and replace BusServices.find(search, {sort: {createdAt: -1}}); with busServicesList.set(BusServices.find(search, {sort: {createdAt: -1}}));.

Perform a search and see the update instantly. Pat yourself on the back. You have accomplished a big job.

This isn't the only approach to implement a search. You can add a route-based implementation, which will subscribe to collection every time you change the route, based on search parameters. However, that isn't efficient because the client has all the data, but still we are asking the server to send the data based on the search parameter.

Reservation

We have reached the last part of the application. We have to allow the user to block or reserve seats in the bus. Also, these actions must be instantaneous to all users, which means both blocking and reservation should reflect in all the users' browsers immediately so that we don't have to manually resolve users' seat selection conflicts. Here, you will see the power of MeteorJS' reactivity:

As usual, we will create a route. Add the following code snippet to routes.js as done earlier:

Router.route("/book/:_id", {
  name: "book",
  layoutTemplate: "createTravelLayout",
  template: "bookTravel",
  waitOn: function () {
    Meteor.subscribe("BlockedSeats", this.params._id);
    Meteor.subscribe("Reservations", this.params._id);
  },
  data: function() {
    templateData = {
      _id: this.params._id,
      bus: BusServices.findOne({_id: this.params._id}),
      reservations: Reservations.find({bus: this.params._id}).fetch(),
      blockedSeats: BlockedSeats.find({bus: this.params._id}).fetch()
    };
    return templateData;
  }
});

Hope you guessed what we are up to. On each record in the list of the listing page, we have a link, which on click will hit this route and the relevant seating layout will appear for the user to block or reserve the seats. What are those new properties in the route? The waitOn property keeps the template rendering to wait until the subscription is completed. We do this because subscriptions are asynchronous. We pass the _id attribute of the bus service to the route and this is passed to the subscription. Similarly, the data property is the place where we can prepare the data that needs to be passed to the templates. Here, we prepare bus details, reservations of the selected bus, and seats that are blocked in this bus; then, send them to the template.

Where will we store all the reservation data? For this, we need a collection. So, let's go to collections.js and add the following:

Reservations = new Meteor.Collection("reservations");

This collection holds seats for reservation. What about blocking? Let's have a collection for that too. Add the following line to the collections.js file:

BlockedSeats = new Meteor.Collection("blockedSeats");

Create the bookTravel directory in the client and add bookTravel.html. file Add the following template code into the file. As you have guessed, we are reusing the same createTravelLayout template as a layout for this interface:

<template name="bookTravel">
  <div class="container busView">
    <div class="row text-center busView__title">{{bus.name}}
    <br />{{bus.agency}}</div>
    <div class="row col-md-4 busView__seats">
      <div class="col-md-12 busView__left">
      {{#each seatArrangement}}
        <div class="col-md-12 row-fluid">
        {{#each this}}
        <div id="seat{{this.seat}}" class="busView__seat {{blocked}} {{reserved}}">{{this.seat}}</div>
        {{#if middleRow}}
          <div class="busView__divider col-md-offset-3"></div>
        {{/if}}
        {{/each}}
        </div>
      {{/each}}
      </div>
    </div>
    <div class="row text-center busView__book"><button id="book" class="btn btn-primary">Book My Seats</button></div>
  </div>
</template>

This template will draw seats in rows and columns based on the total seats stored in the busservices collection document. The idea is to get the data of the interested bus service, reservations made so far for the same bus, and seats blocked at the moment for the same bus. Once we get all the data, we draw the seating layout with the blocked and reservation information.

We need a few helpers and event handlers to get this entire stuff done. Create bookTravelHelper.js inside the bookTravel directory and add the following code:

Template.bookTravel.helpers({
  seatArrangement: function() {
    var arrangement = [],
      totalSeats = (this.bus || {}).seats || 0,
      blockedSeats = _.map(this.blockedSeats || [], function(item) {return item.seat}),
      reservedSeats = _.flatten(_.map(this.reservations || [], function(item) {return _.map(item.seatsBooked, function(seat){return seat.seat;});})),
      tmpIndex = 0;
      Session.set("blockedSeats", this.blockedSeats);
    arrangement[tmpIndex] = [];
    for(var l = 1; l <= totalSeats; l++) {
      arrangement[tmpIndex].push({
        seat: l, 
        blocked: blockedSeats.indexOf(l) >= 0 ? "blocked" : "", 
        reserved: reservedSeats.indexOf(l) >= 0 ? "reserved" : "",
    });
      if(l % 4 === 0 && l != totalSeats) {
        tmpIndex++;
        arrangement[tmpIndex] = arrangement[tmpIndex] || [];
      }
    }
    return arrangement;
  },
  middleRow: function () {
    return (this.seat % 2) === 0;
  }
});
Template.bookTravel.events({
  "click .busView__seat:not(.reserved):not(.blocked)": function (e) {
    e.target.classList.add("blocked");
    var seat = {
      bus: Template.currentData().bus._id,
      seat: parseInt(e.target.id.replace("seat", ""), 10),
      blockedBy: ""
    };
    Meteor.call("blockThisSeat", seat, function(err, result) {
      if(err) {
        e.target.classList.remove("blocked");
      } else {
        var blockedSeats = Session.get("blockedSeats") || [];
        blockedSeats.push(seat);
        Session.set("blockedSeats", blockedSeats);
      }
    });
  },
  "click #book": function() {
    var blockedSeats = Session.get("blockedSeats");
    if(blockedSeats && blockedSeats.length) {
      Meteor.call("bookMySeats", blockedSeats, function (error, result) {
      if(result) {
          Meteor.call("unblockTheseSeats", blockedSeats, function() {
            Session.set("blockedSeats", []);
          });
        } else {
          alert("Reservation failed");
          console.log(error);
        }
      });
    } else {
      alert("No seat selected");
    }
  }
});

The helper method seatArrangement will aggregate the reservation and the blocked seats data along with the seat information in a way which will be easy to render. The middleRow helper method is used to do a small modulus operation to have a gap between the second and the third column.

The event handler on each seat will call the server to persist the blocking action. Clicking on the book button will call the server to reserve the blocked seats.

Let's get into the server section. We have to publish both the newly created collections to the client and also add a method that the client is calling to persist the data.

Create the reservations.js file in the server directory and add the following code:

Meteor.methods({
  /**
    seatsBooked: [{seat: #}]
    bus
    createdAt
    updatedAt
  **/
  bookMySeats: function(reservations) {
    var insertRes = reservations.map(function(res) {
      return {
        seat: res.seat
      }
    });
    return Reservations.insert({
      bus: reservations[0].bus,
      seatsBooked: insertRes,
      createdAt: new Date(),
      updatedAt: null
    }, function (error, result) {
      console.log("Inside res insert", arguments);
      if(result) {
        BusServices.update({_id: reservations[0].bus}, {
          $set: {
            updatedAt: new Date()
          },
            $inc: {
            available_seats: -insertRes.length
          }
        }, function() {});
      }
    });
  }
});
Meteor.publish("Reservations", function (id) {
    return Reservations.find({bus: id}, {sort: {createdAt: -1}});
});

Similarly, create the bookTravel.js file and add the following code:

Meteor.methods({
  blockThisSeat: function(seat) {
    var insertedDocId;
    seat.createdAt = new Date();
    seat.updatedAt = null;
    BlockedSeats.insert(seat, function(error, result) {
      if(error) {
        throw Meteor.Error("Block seat failed");
      } else {
        insertedDocId = result;
      }
    });
    Meteor.setTimeout(function() {
      BlockedSeats.remove({_id: insertedDocId});
    }, 600000);// 10 mins
  },
  unblockTheseSeats: function(seats) {
    seats.forEach(function (seat) {
      BlockedSeats.remove({_id: seat._id});
    });
  }
});

Meteor.publish("BlockedSeats", function (id) {
  return BlockedSeats.find({bus: id});
});

If you look at the event handlers that we created for the bookTravel template, you will find these method calls. All they do is persist data. Also, a blocked seat will be released after 10 minutes and you can see that happening in the blockThisSeat server method. A timer is registered on each call. Let us see things in action.

Open the same booking page in another browser. You will find the seat arrangement and reservation data, if any, as shown in the following image:

Reservation

Reserve or block some seats and visit the page in the other browser. You will see the changes instantly appearing here. Also, our event handler will not allow the user on any end to choose seats that are reserved or blocked. This is the actual power of MeteorJS. Instant reactivity on any data change to all clients without any special effort from the developer will drastically reduce your development effort.

Summary

I hope you have enjoyed this chapter. There is a lot of scope to improve the application in terms of features. Go play around and implement additional features and get your hands dirty. I will leave it to your imagination. This chapter has come to an end. Let's summarize what we have learned so far. MeteorJS is built by integrating various packages. MeteorJS employs various components on the server, client, and channel to build the applications. MeteorJS provides extensive and flexible APIs to create customized logins. We can define named routes, and thereby associate templates and layouts with the route. We have also learned how to use multiple layouts in the application. We also learned to code database operations, query for search operations, sever side method calls, and custom reactive variables to make the application more lively and reactive.

What we have learned so far is good. However, there is a lot we can improve in this whole process. In the next chapter, we'll learn how to develop MeteorJS application like a pro.

Left arrow icon Right arrow icon

Key benefits

  • • Get your dream project up and running by building exceptional MeteorJS applications in a matter of days
  • • Learn how to integrate other JavaScript frameworks into your MeteorJS project and become an expert in full-stack development
  • • Go beyond coding and learn how to make modern design decisions – from mobile design to SEO – that drive great user experiences

Description

The web is dead – applications now rule our online experiences. But how are you going to build them? Well, if you’ve been paying attention, you might already have tried your hand with MeteorJS, the JavaScript framework that helps you build complete full-stack web applications that are responsive and fast with ease. Mastering MeteorJS Application Development shows you how to do even more with MeteorJS – if you’re ready to try a comprehensive course through one of the most exciting frameworks in web development today, this is the book you need. Designed to take you through the entire process of building an advanced multipage application with Meteor, you’ll be able to bring your web development ideas with surprising ease. You’ll not only learn how Meteor makes web development easier, but also how you can make using Meteor easier, by automating and simplifying tasks so you can be confident you have full control of everything in your workflow – especially everything that could go wrong. From automated testing to integrating other useful frameworks such as Angular and D3, each chapter covers a crucial element in the Meteor development process. Discover how to integrate animations using Meteor’s Blaze, to give your UI designs the edge, and explore reactive programming to effectively harness RESTful systems in your projects. You will also learn how to deploy and scale your application, two crucial aspects of modern development and vital in a changing digital environment with users expecting a product and experience that delivers. With further insights on developing for mobile – and how Meteor can help you tackle the challenges of the trend – and details on incorporating SEO strategies into your application, this book isn’t just a code tutorial – it’s about creating a product that users love.

Who is this book for?

If you’ve already had some experience with MeteorJS but want to learn how to build even better modern web application, this book has been created for you. It provides you with a comprehensive look at one of those most important frameworks being used for the modern web today.

What you will learn

  • • Get to grips with the basics and learn how to build a complete real-time application with MeteorJS
  • • Find out how Meteor makes full-stack development simple – become a better developer, fast.
  • • Use some of the most effective testing tools in modern web development to troubleshoot, debug and optimize your app
  • • Find out how to write custom packages for applications – so you can build your project exactly how you want
  • • Integrate React and Angular into your project
  • • Design and develop high quality animations that will give your UI the edge
  • Build MeteorJS to serve as REST-based application and reactive system
  • Learn how to host a MeteorJS application and then scale it for data• Find out how MeteorJS can help you build for mobile
  • Learn how to make sure you implement an effective SEO strategy in your MeteorJS application
Estimated delivery fee Deliver to Taiwan

Standard delivery 10 - 13 business days

$12.95

Premium delivery 5 - 8 business days

$45.95
(Includes tracking information)

Product Details

Country selected
Publication date, Length, Edition, Language, ISBN-13
Publication date : Dec 30, 2015
Length: 298 pages
Edition : 1st
Language : English
ISBN-13 : 9781785282379
Languages :
Tools :

What do you get with Print?

Product feature icon Instant access to your digital eBook copy whilst your Print order is Shipped
Product feature icon Paperback book shipped to your preferred address
Product feature icon Download this book in EPUB and PDF formats
Product feature icon Access this title in our online reader with advanced features
Product feature icon DRM FREE - Read whenever, wherever and however you want
OR
Modal Close icon
Payment Processing...
tick Completed

Shipping Address

Billing Address

Shipping Methods
Estimated delivery fee Deliver to Taiwan

Standard delivery 10 - 13 business days

$12.95

Premium delivery 5 - 8 business days

$45.95
(Includes tracking information)

Product Details

Publication date : Dec 30, 2015
Length: 298 pages
Edition : 1st
Language : English
ISBN-13 : 9781785282379
Languages :
Tools :

Packt Subscriptions

See our plans and pricing
Modal Close icon
$19.99 billed monthly
Feature tick icon Unlimited access to Packt's library of 7,000+ practical books and videos
Feature tick icon Constantly refreshed with 50+ new titles a month
Feature tick icon Exclusive Early access to books as they're written
Feature tick icon Solve problems while you work with advanced search and reference features
Feature tick icon Offline reading on the mobile app
Feature tick icon Simple pricing, no contract
$199.99 billed annually
Feature tick icon Unlimited access to Packt's library of 7,000+ practical books and videos
Feature tick icon Constantly refreshed with 50+ new titles a month
Feature tick icon Exclusive Early access to books as they're written
Feature tick icon Solve problems while you work with advanced search and reference features
Feature tick icon Offline reading on the mobile app
Feature tick icon Choose a DRM-free eBook or Video every month to keep
Feature tick icon PLUS own as many other DRM-free eBooks or Videos as you like for just $5 each
Feature tick icon Exclusive print discounts
$279.99 billed in 18 months
Feature tick icon Unlimited access to Packt's library of 7,000+ practical books and videos
Feature tick icon Constantly refreshed with 50+ new titles a month
Feature tick icon Exclusive Early access to books as they're written
Feature tick icon Solve problems while you work with advanced search and reference features
Feature tick icon Offline reading on the mobile app
Feature tick icon Choose a DRM-free eBook or Video every month to keep
Feature tick icon PLUS own as many other DRM-free eBooks or Videos as you like for just $5 each
Feature tick icon Exclusive print discounts

Frequently bought together


Stars icon
Total $ 131.97
Mastering MeteorJS Application Development
$48.99
Meteor Design Patterns
$38.99
Meteor Cookbook
$43.99
Total $ 131.97 Stars icon
Banner background image

Table of Contents

10 Chapters
1. Building a MeteorJS Web Application Chevron down icon Chevron up icon
2. Developing and Testing an Advanced Application Chevron down icon Chevron up icon
3. Developing Reusable Packages Chevron down icon Chevron up icon
4. Integrating Your Favorite Frameworks Chevron down icon Chevron up icon
5. Captivating Your Users with Animation Chevron down icon Chevron up icon
6. Reactive Systems and REST-Based Systems Chevron down icon Chevron up icon
7. Deploying and Scaling MeteorJS Applications Chevron down icon Chevron up icon
8. Mobile Application Development Chevron down icon Chevron up icon
9. Best Practices, Patterns, and SEO Chevron down icon Chevron up icon
Index Chevron down icon Chevron up icon

Customer reviews

Rating distribution
Full star icon Full star icon Full star icon Full star icon Empty star icon 4
(5 Ratings)
5 star 60%
4 star 20%
3 star 0%
2 star 0%
1 star 20%
jaclynn Jan 14, 2016
Full star icon Full star icon Full star icon Full star icon Full star icon 5
This book filled in many missing pieces for me. Meteor is one of those frameworks where you can build something really slick, really fast, without necessarily understanding some of the underlying components. This has been my experience. I built an app in a couple days, it worked really well, I had a lot of fun, but then when I'd go in the Meteor forums or listen to the Meteor podcasts, I felt a bit lost. Wanting to up my game, I thought the best way might be to study JavaScript, Mongo and Node more in depth. This helped, but there were still parts of Meteor that seemed like dark magic. I found the author's explanations of how Blaze and Tracker work with oplog and MiniMongo much easier to understand.The first chapter has the reader create an application using standard Meteor with simple routing. Subsequent chapters have the reader recreating that app, or building out new apps using new techniques and tools. The timing of this book could have been unfortunate given that Meteor is undergoing some changes prior to 1.3. The author spends time on Iron Router and Velocity... which seem to be in the process of deprecation.(...) and (...) . However, those components have a strong footprint in existing apps, and the author does cover Flow Router. If you already develop in AngularJS and React, or would like to use them instead of Blaze, they are covered in their own sections. Finally, topics like animation and mobile app development are covered... ones that are a little more difficult to find on the web in the forms of tutorials.FWIW, I purchased this as an ebook from the publisher prior to its release. It has exceeded my expectations.
Amazon Verified review Amazon
R. S. Jan 17, 2016
Full star icon Full star icon Full star icon Full star icon Full star icon 5
A must have for Meteor JS developer!All you need to know to create great and professional apps with Meteor is in it. The book is really helpful, even for an advanced Meteor JS developer.We start with a little app to build, then we increase our skills by adding debug and tests. After that, let's split the application into reusable packages.Also, the book explain how to use other JS technos with Meteor (like React, Angular, but also D3.Of course, some chapters explains you how to deploy and maintain your app after build it, with SSL support, scalability and other advanced stuff.Even if a lot of documentation is available online, this is really the missing MeteorJS book!A really thanks to the author, Jebin B V, for his work which reflect, I think, his passion for the great web development in JS.Great job!
Amazon Verified review Amazon
tlemeur Jan 16, 2016
Full star icon Full star icon Full star icon Full star icon Full star icon 5
Coming from the PHP environment, I always was reluctant to change my habits and switch to Javascript (which in my mind was not well suited to server-side operations). This was before I discovered MeteorJS. After having completed some video tutorials on the net, I was convinced that meteor was the way to go.However when you really dive into building a complex application you're quickly stuck on real life concerns such as:* how to structure your code (file organization, packages),* how to manage your data schema to ease maintenance,* how to integrate with other client-side libraries (such as D3) or frameworks (for instance Angular),* and of course how to test and deployThis "Mastering MeteorJS Application Developpement" book covers it all in a clear way.Though I still consider myself a newbie in the MeteorJS planet, I feel confident that this book will be a great asset in my journey to MeteorJS developpment. How do I know ? Well it's simple, each time I tried to use MeteorJS for real life applications I found out that I needed a deeper understanding of some packages, or some MeteorJS insights, or just wondering how to organize my work... and it turned out that this book covers most of the topics I had on my "to-do/to-learn list".I would then recommend to use this tool in 2 different manners:* as an advanced course on improving your workflow, learn best practices, and point to great add-on packages available on the Atmosphere* as a reference guide for the subjects coveredAs a conclusion, I recommend this book for those having a good background on MeteorJS and who want to imporve their workflow to become more efficient and produce better code.(As the previous reviewer, I bought this book as an ebook before release, and I'm not disappointed)
Amazon Verified review Amazon
Amazon Customer Aug 26, 2017
Full star icon Full star icon Full star icon Full star icon Empty star icon 4
The book offers a good amount of information about how MeteorJS works, and how to use tools to develop for the framework in a professional way. It presents the information fairly clearly, despite many glaringly obvious grammatical and spelling mistakes. There are only a few points where the author was hard to understand. Some of my favorite sections of the book were where the author explains how Tracker works in great detail, as well as how to package, deploy, and scale MeteorJS applications using several different methods.
Amazon Verified review Amazon
tkent Sep 13, 2017
Full star icon Empty star icon Empty star icon Empty star icon Empty star icon 1
Save your money. This book is not worthless but close. Meteor in Action by Hochhaus and Schoebel is a better reference.
Amazon Verified review Amazon
Get free access to Packt library with over 7500+ books and video courses for 7 days!
Start Free Trial

FAQs

What is the delivery time and cost of print book? Chevron down icon Chevron up icon

Shipping Details

USA:

'

Economy: Delivery to most addresses in the US within 10-15 business days

Premium: Trackable Delivery to most addresses in the US within 3-8 business days

UK:

Economy: Delivery to most addresses in the U.K. within 7-9 business days.
Shipments are not trackable

Premium: Trackable delivery to most addresses in the U.K. within 3-4 business days!
Add one extra business day for deliveries to Northern Ireland and Scottish Highlands and islands

EU:

Premium: Trackable delivery to most EU destinations within 4-9 business days.

Australia:

Economy: Can deliver to P. O. Boxes and private residences.
Trackable service with delivery to addresses in Australia only.
Delivery time ranges from 7-9 business days for VIC and 8-10 business days for Interstate metro
Delivery time is up to 15 business days for remote areas of WA, NT & QLD.

Premium: Delivery to addresses in Australia only
Trackable delivery to most P. O. Boxes and private residences in Australia within 4-5 days based on the distance to a destination following dispatch.

India:

Premium: Delivery to most Indian addresses within 5-6 business days

Rest of the World:

Premium: Countries in the American continent: Trackable delivery to most countries within 4-7 business days

Asia:

Premium: Delivery to most Asian addresses within 5-9 business days

Disclaimer:
All orders received before 5 PM U.K time would start printing from the next business day. So the estimated delivery times start from the next day as well. Orders received after 5 PM U.K time (in our internal systems) on a business day or anytime on the weekend will begin printing the second to next business day. For example, an order placed at 11 AM today will begin printing tomorrow, whereas an order placed at 9 PM tonight will begin printing the day after tomorrow.


Unfortunately, due to several restrictions, we are unable to ship to the following countries:

  1. Afghanistan
  2. American Samoa
  3. Belarus
  4. Brunei Darussalam
  5. Central African Republic
  6. The Democratic Republic of Congo
  7. Eritrea
  8. Guinea-bissau
  9. Iran
  10. Lebanon
  11. Libiya Arab Jamahriya
  12. Somalia
  13. Sudan
  14. Russian Federation
  15. Syrian Arab Republic
  16. Ukraine
  17. Venezuela
What is custom duty/charge? Chevron down icon Chevron up icon

Customs duty are charges levied on goods when they cross international borders. It is a tax that is imposed on imported goods. These duties are charged by special authorities and bodies created by local governments and are meant to protect local industries, economies, and businesses.

Do I have to pay customs charges for the print book order? Chevron down icon Chevron up icon

The orders shipped to the countries that are listed under EU27 will not bear custom charges. They are paid by Packt as part of the order.

List of EU27 countries: www.gov.uk/eu-eea:

A custom duty or localized taxes may be applicable on the shipment and would be charged by the recipient country outside of the EU27 which should be paid by the customer and these duties are not included in the shipping charges been charged on the order.

How do I know my custom duty charges? Chevron down icon Chevron up icon

The amount of duty payable varies greatly depending on the imported goods, the country of origin and several other factors like the total invoice amount or dimensions like weight, and other such criteria applicable in your country.

For example:

  • If you live in Mexico, and the declared value of your ordered items is over $ 50, for you to receive a package, you will have to pay additional import tax of 19% which will be $ 9.50 to the courier service.
  • Whereas if you live in Turkey, and the declared value of your ordered items is over € 22, for you to receive a package, you will have to pay additional import tax of 18% which will be € 3.96 to the courier service.
How can I cancel my order? Chevron down icon Chevron up icon

Cancellation Policy for Published Printed Books:

You can cancel any order within 1 hour of placing the order. Simply contact customercare@packt.com with your order details or payment transaction id. If your order has already started the shipment process, we will do our best to stop it. However, if it is already on the way to you then when you receive it, you can contact us at customercare@packt.com using the returns and refund process.

Please understand that Packt Publishing cannot provide refunds or cancel any order except for the cases described in our Return Policy (i.e. Packt Publishing agrees to replace your printed book because it arrives damaged or material defect in book), Packt Publishing will not accept returns.

What is your returns and refunds policy? Chevron down icon Chevron up icon

Return Policy:

We want you to be happy with your purchase from Packtpub.com. We will not hassle you with returning print books to us. If the print book you receive from us is incorrect, damaged, doesn't work or is unacceptably late, please contact Customer Relations Team on customercare@packt.com with the order number and issue details as explained below:

  1. If you ordered (eBook, Video or Print Book) incorrectly or accidentally, please contact Customer Relations Team on customercare@packt.com within one hour of placing the order and we will replace/refund you the item cost.
  2. Sadly, if your eBook or Video file is faulty or a fault occurs during the eBook or Video being made available to you, i.e. during download then you should contact Customer Relations Team within 14 days of purchase on customercare@packt.com who will be able to resolve this issue for you.
  3. You will have a choice of replacement or refund of the problem items.(damaged, defective or incorrect)
  4. Once Customer Care Team confirms that you will be refunded, you should receive the refund within 10 to 12 working days.
  5. If you are only requesting a refund of one book from a multiple order, then we will refund you the appropriate single item.
  6. Where the items were shipped under a free shipping offer, there will be no shipping costs to refund.

On the off chance your printed book arrives damaged, with book material defect, contact our Customer Relation Team on customercare@packt.com within 14 days of receipt of the book with appropriate evidence of damage and we will work with you to secure a replacement copy, if necessary. Please note that each printed book you order from us is individually made by Packt's professional book-printing partner which is on a print-on-demand basis.

What tax is charged? Chevron down icon Chevron up icon

Currently, no tax is charged on the purchase of any print book (subject to change based on the laws and regulations). A localized VAT fee is charged only to our European and UK customers on eBooks, Video and subscriptions that they buy. GST is charged to Indian customers for eBooks and video purchases.

What payment methods can I use? Chevron down icon Chevron up icon

You can pay with the following card types:

  1. Visa Debit
  2. Visa Credit
  3. MasterCard
  4. PayPal
What is the delivery time and cost of print books? Chevron down icon Chevron up icon

Shipping Details

USA:

'

Economy: Delivery to most addresses in the US within 10-15 business days

Premium: Trackable Delivery to most addresses in the US within 3-8 business days

UK:

Economy: Delivery to most addresses in the U.K. within 7-9 business days.
Shipments are not trackable

Premium: Trackable delivery to most addresses in the U.K. within 3-4 business days!
Add one extra business day for deliveries to Northern Ireland and Scottish Highlands and islands

EU:

Premium: Trackable delivery to most EU destinations within 4-9 business days.

Australia:

Economy: Can deliver to P. O. Boxes and private residences.
Trackable service with delivery to addresses in Australia only.
Delivery time ranges from 7-9 business days for VIC and 8-10 business days for Interstate metro
Delivery time is up to 15 business days for remote areas of WA, NT & QLD.

Premium: Delivery to addresses in Australia only
Trackable delivery to most P. O. Boxes and private residences in Australia within 4-5 days based on the distance to a destination following dispatch.

India:

Premium: Delivery to most Indian addresses within 5-6 business days

Rest of the World:

Premium: Countries in the American continent: Trackable delivery to most countries within 4-7 business days

Asia:

Premium: Delivery to most Asian addresses within 5-9 business days

Disclaimer:
All orders received before 5 PM U.K time would start printing from the next business day. So the estimated delivery times start from the next day as well. Orders received after 5 PM U.K time (in our internal systems) on a business day or anytime on the weekend will begin printing the second to next business day. For example, an order placed at 11 AM today will begin printing tomorrow, whereas an order placed at 9 PM tonight will begin printing the day after tomorrow.


Unfortunately, due to several restrictions, we are unable to ship to the following countries:

  1. Afghanistan
  2. American Samoa
  3. Belarus
  4. Brunei Darussalam
  5. Central African Republic
  6. The Democratic Republic of Congo
  7. Eritrea
  8. Guinea-bissau
  9. Iran
  10. Lebanon
  11. Libiya Arab Jamahriya
  12. Somalia
  13. Sudan
  14. Russian Federation
  15. Syrian Arab Republic
  16. Ukraine
  17. Venezuela