This document provides an overview of the Meteor JavaScript web application framework. It discusses key Meteor concepts like Blaze for creating reactive UIs, Tracker for transparent reactive programming, and data contexts that are set implicitly through template tags and passed between templates. The document also covers Spacebars templating syntax and how data contexts work in templates, template helpers, and with Iron Router.
2. Attribution
• The material contained inside is intended for teaching.
• This document is licensed under the CC BY-NC-SA license.
• Relevant sources are listed on the following References slide.
• All figures and text borrowed from these sources retain the rights of
their respective owners.
2/56
3. References
• Websites
• Official website
• Meteor on Twitter
• Meteor on GitHub
• Meteor on StackOverflow
• forums.meteor.com - Meteor discussion forums
• crater.io - Meteor News
• Books
• Turnbull, David - Your First Meteor Application (2014)
• Coleman, Tom; Greif, Sacha - Discover Meteor (2014)
• Hochhaus, Stephan; Schoebel, Manuel - Meteor in Action (2014)
• Susiripala, Arunoda - Bulletproof Meteor (2014)
• Susiripala, Arunoda - Meteor Explained - A Journey Into Meteor’s Reactivity (2014)
• Strack, Isaac - Getting started with Meteor.js JavaScript framework (2012)
• http://meteorcapture.com/
3/56
4. Acknowledgments & Warning
• Special thanks to all the authors of the documents cited in the
references for their high-quality teaching material from which I have
borrowed extensively.
• This material has been written in late 2015 and as Meteor is a fast
moving target, some parts may be outdated.
4/56
5. Table of Contents
1. Presentation
2. Principles
3. Templates
4. Sessions
5. Spacebars
6. Data contexts
7. Routing with Iron Router
8. Modules & packages
9. Misc
5/56
7. Meteor
• Open-source JavaScript web application framework
• Backend
• Uses Node.js
• Integrates with MongoDB
• uses the Distributed Data Protocol
• uses a publish–subscribe pattern to propagate data changes to clients without
writing any synchronization code
• Frontend
• depends on jQuery (Blaze = reactive jQuery)
• can be used with any JavaScript UI widget library (e.g., Bootstrap)
7/56
9. Blaze
• Library for creating UIs by writing reactive HTML templates
• Combination of traditional templates and jQuery requires "update logic" in your app that listens for data changes and
manipulates the DOM
• Instead, template directives like {{#if}} and {{#each}} integrate with Tracker's "transparent reactivity" and Minimongo's
database cursors so that the DOM updates automatically
• Blaze has two major parts
• A compiler from template files into JavaScript code that runs against the Blaze runtime library
• Moreover, Blaze provides a compiler toolchain (think LLVM) that can be used to support arbitrary template syntaxes
• The flagship template syntax is Spacebars, a variant of Handlebars
• Community alternative based on Jade is already in use by many apps
• A reactive DOM engine that builds and manages the DOM at runtime
• invoked via templates or directly from the app
• features reactively updating regions, lists, and attributes; event delegation; callbacks and hooks
• Similar to frameworks like React, Angular, Ember, Polymer, Knockout, etc.
• focus on the developer experience, using templating, transparent reactivity, and interoperability with existing libraries
• gentle learning curve
• It hooks into jQuery's clean-up routines to prevent memory leaks, and it preserves classes, attributes, and
styles added to elements by jQuery or any third-party library
9/56
10. Tracker
• Library for transparent reactive programming in JavaScript
• Formerly called Deps
• Functional Reactive Programming (FRP) system without requiring you to
rewrite your program as a FRP data flow graph
• Combined with Tracker-aware libraries, this lets you build complex event-
driven programs without writing a lot of boilerplate event-handling code
• A simple convention, or interface, that lets reactive data sources (database)
talk to reactive data consumers (live-updating HTML templating library)
without the application code in between having to be involved
• Since the convention is very simple, it is quick and easy for library authors
to make their libraries Tracker-aware, so that they can participate in
Tracker reactivity
10/56
11. Alternative web application frameworks
Project Current stable version Release date License
AngularJS 1.4.0 2015-05-26 MIT License
KnockoutJS 3.2.0 2014-08-12 MIT License
Backbone.js 1.1.2 2014-02-20 MIT License
Ember.js 2.0.2 2015-09-07 MIT License
OpenUI5 1.26.8 2015-03-10
Apache 2.0 License by
SAP
Express.js 4.12.3 2015-03-17 MIT License
Unified.js 14.0 2014-04-01
BSD (component only) &
proprietary
11/56
13. Principles of Meteor
• Data on the Wire
• Meteor doesn't send HTML over the network. The server sends data and lets the client render it
• One Language
• both the client and the server parts of your application written in JavaScript
• Database Everywhere
• same methods to access your database from the client or the server
• Latency Compensation
• On the client, Meteor prefetches data and simulates models to make it look like server method calls return
instantly
• Full Stack Reactivity
• All layers, from database to template, update themselves automatically when necessary
• Embrace the Ecosystem
• Meteor is open source and integrates with existing open source tools and frameworks
• Simplicity Equals Productivity
• Meteor's main functionality has clean, classically beautiful APIs
13/56
15. Code rules in Meteor
• Code simultaneously runs in two different environments
• on the client and on the server
• Code behaves differently depending on the environment
• Sometimes we don’t want our code to run in both places
• use booleans Meteor.isClient / Meteor.isServer
• place code in client/ or in server/ folders
• Code in client/ always runs on the client
• Code in server/ always runs on server and is never sent to the client
15/56
16. Variable/function scope in Meteor
• Variables in Meteor declared with the var keyword are scoped to the
file they are declared in
• To define a global variable, don't write the var keyword
• someVarname = 'someValue';
• To define a global function, assign it to a global var
• someFun = function someFun() {...}
• This will define a variable/function in all your application by default
• you may restrict it by writing that declaration in a specific recognized folder
(client or server folder for example)
16/56
20. Collections
Tasks = new Mongo.Collection("dbtasks");
Tasks.insert({ text: "Hello world!",
createdAt: new Date() });
if (Meteor.isClient) {
Template.tasklist.helpers({
tasks: function () {
return Tasks.find({}, {sort:
{createdAt: -1}});
}
});
}
• Built from MongoDB collections
• dbtasks
• Global JS variables
• Both in client and server
• Minimongo on the client
• Auto synchronization
20/56
21. Events for insertion
<template name="tasklist">
<form class="new-task">
<input type="text"
name="text"
placeholder="Type in new
tasks" />
</form>
</template>
Template.tasklist.events({
"submit .new-task": function(event) {
event.preventDefault();
var text = event.target.text.value;
Tasks.insert({
text: text,
createdAt: new Date()
});
event.target.text.value = "";
}
});
21/56
22. Events for update and deletion
<template name="task">
<li class="{{#if checked}}checked{{/if}}">
<button class="delete">×</button>
<input type="checkbox"
checked="{{checked}}"
class="toggle-checked" />
<span class="text">{{text}}</span>
</li>
</template>
Template.task.events({
"click .toggle-checked": function() {
Tasks.update(this._id, {
$set: {checked: ! this.checked}
});
},
"click .delete": function() {
Tasks.remove(this._id);
}
});
this refers to a
task objet (= DC)
_id refers to its
MongoDB id
$set refers to a
MongoDB operator
22/56
25. Session as a reactive data store for the client
• State is usually stored in collections
• the view updates automatically when the data inside these collections are
modified
• Mongo.Collection is recognized by Meteor as a reactive data source
• Meteor knows when the data inside has changed
• Session is the same way, but is not synced with the server like
collections are
• convenient place to store temporary UI state
• No need to write any extra code for the template to update when the Session
variable changes — just calling Session.get(...) inside the helper is enough
25/56
26. EJSON
• EJSON is an extension of JSON to support more types
• It supports all JSON-safe types
• Date (JavaScript Date)
• Binary (JavaScript Uint8Array or the result of EJSON.newBinary)
• User-defined types (see EJSON.addType. For example, Mongo.ObjectID is implemented this way.)
• All EJSON serializations are also valid JSON
• For example an object with a date and a binary buffer would be serialized in EJSON as
{ "d": {"$date": 1358205756553},
"b": {"$binary": "c3VyZS4="} }
• Meteor supports all built-in EJSON data types in
• publishers
• method arguments and results
• Mongo databases
• Session variables
26/56
28. Spacebars
• Four major types of template tags
• {{pageTitle}} - Double-braced template tags are used to insert a string of text.
The text is automatically made safe. It may contain any characters (like <) and
will never produce HTML tags.
• {{> nav}} - Inclusion template tags are used to insert another template by
name.
• {{#each}} - The block tags #if, #each, #with, and #unless are built in, and it is
also possible to define custom ones. Some block tags, like #each and #with,
establish a new data context for evaluating their contents.
• {{{content}}} - Triple-braced template tags are used to insert raw HTML.
28/56
30. Identifiers and Paths
• A Spacebars identifier is either
• a JavaScript identifier name
• any string enclosed in square brackets ( [ and ] )
• The special identifiers this (or equivalently, .) and ..
• Brackets are required to use one of the following as the first element of a path: else, this, true, false, and null
• Brackets are not required around JavaScript keywords and reserved words like var and for
• A Spacebars path is a series of one or more identifiers separated by either . or /
• E.g., foo, foo.bar, this.name, ../title, or foo.[0] (numeric indices must be enclosed in brackets)
• Name Resolution
• The first identifier in a path is resolved in one of two ways
• Indexing the current data context. The identifier foo refers to the foo property of the current data context object.
• As a template helper. The identifier foo refers to a helper function (or constant value) that is accessible from the current template.
• Template helpers take priority over properties of the data context
• If a path starts with .. , then the enclosing data context is used instead of the current one. The enclosing data context might be the one outside
the current #each, #with, or template inclusion.
• Path Evaluation
• When evaluating a path, identifiers after the first are used to index into the object so far, like JavaScript's .(dot) . However, an error is never
thrown when trying to index into a non-object or an undefined value.
• In addition, Spacebars will call functions for you, so {{foo.bar}} may be taken to mean foo().bar, foo.bar(), or foo().bar() as appropriate.
30/56
31. Spacebars caveats
• In Spacebars, the Data Context is the only way to
pass data from template to template
• Data Context can be accessed with the this keyword
• It is inherited by default on templates inclusions, so it
sneaks into everything
• It is silent and the only argument, it is also implicit
• Constructs like #each and #with change the data
context in such a way that access to the parent
data must be done with a weird dotted syntax
• The reason for such syntax is the concept of
"paths" in Spacebars
• A construct like {{person.bio.homeTown}} is not a
property access: it is a path
• The {{../name}} construct makes sense as a path
• Expression {{.}} is equivalent to {{this}}
• Data context is a dynamic variable, that depends
on the chain of calls that led here, rather than the
environment that existed when the template was
defined (lexical variable)
• JavaScript has only one sort-of dynamic variable
called this and people are confused by it
• In JavaScript this is not the main way of passing
arguments to a function
• In Handlebars it is the only way
• Handlebars’ {{#with}} and JavaScript with keyword
• It makes the code confusing, it cripples the scope, it is a
source of bugs, it is deprecated in the strict mode
31/56
33. Data contexts by template tags
• set and used implicitly
• great time-saver
• source of confusion and ambiguity
• set a data context with the {{#with}} and {{/with}} template tags
• {{#with}} takes an argument which becomes the data context of the block enclosed
within the tag
• {{#with}} can be nested to easily access nested objects
• Set a DC with the {{#each}} and {{/each}} helper tags
• {{#each}} takes an argument, usually a cursor resulting of a Collection.find() call
• {{#each}} will then loop over that argument, and set the data context for each
iteration of the loop
33/56
34. Data contexts by template inclusion
• The profile template’s data context can be set to author as it is included from
within that post template
<template name="post">
{{#with post}}
<p>{{content}}</p>
<div>{{> profile author}}</div>
{{/with}}
</template>
• This won’t work if a data context is set inside the profile template (e.g., with a
{{#with}} tag)
34/56
35. Data contexts by Iron Router
• Iron Router can set and manipulate data contexts through its data function
this.route('profile', {
path: '/profile/:_id',
template: 'profile',
data: function() {
return Users.findOne(this.params._id);
}
});
• Defines a route that brings up the profile template while setting its data context to
Users.findOne(this.params._id)
• Setting the data context in the router instead of the template makes it much easier to reuse your template
for different data contexts
35/56
36. Data contexts in JS template helpers
• In a template helper, the data context is
accessible through the this keyword
• A template helper will inherit its data context from
the template itself
• Depending on where you call a template helper, it
might end up with a completely different data
context!
• Because the template’s {{#with}} tag sets the
data context to the name property of the
profile object, the avatarPath and fullName
helpers will end up having different data
contexts, even though they belong to the
same template
<template name="profile">
{{#with profile}}
<img src="{{avatarPath}}"/>
{{#with name}}
<p>{{fullName}}</p>
{{/with}}
{{/with}}
</template>
Template.profile.helpers({
profile: function(){return Users.findOne(Session.get(‘aUserId'));},
avatarPath: function () { // data context set to profile
return "images/" + this.avatar; },
fullName: function () { // data context set to profile.name
return this.first + " " + this.last; }
});
36/56
37. Parent Data Context Access
• Access to the parent’s DC with the .. keyword
• Access to the grandparent’s DC with the ../.. keyword
• Access to any ascendant with
Template.parentData([numLevels])
• access the parent DC by passing `1` as the parameter
<template name="profile">
{{#with profile}}
<img src="{{avatarPath}}"/>
{{#with name}}
{{parentHelper ..}}
<p>{{fullName}}</p>
{{/with}}
{{/with}}
</template>
Template.profile.helpers({
parentHelper: function (parentContext) {
console.log(this); // profile.name data context
console.log(parentContext); // profile data context
}
});
37/56
38. Data Context in Templates
• A “t2” template called within the
“t1” template has access to all
the same data that the “t1”
template has access to
• Data is “trickling down” between
templates which is extremely
useful
38/56
40. Routing with Iron Router
• Routes are used to associate a
URL path with a template
• By default, routes are created for
the client and will run in the
browser
<template name="register">
<h2>Register</h2>
</template>
• Inside the JS file (but outside the
isClient and isServer
conditionals), write
Router.route('/register');
• The following URL is created
http://localhost:3000/register
40/56
41. Linking routes
• Use hard-coded links
<a href="/register">Register</a>
• If the path of the “/register” route
changes, the link will break
• Define a name for each route
Router.route('/', {
name: 'home',
template: 'home'
});
<a href="{{pathFor route='home'}}">
Home</a>
• Use pathFor tag to pass through
the name of a route
• The link will continue to work if the
path of the route ever changes
• The link will only break if the name
of the route is changed
• If name is undefined, the name of
the route will be equal to its path
41/56
42. Route options
• Associate path to template
Router.route('/', {
template: 'home'
});
• Associate name to path
Router.route('/tata', {
name: ‘titi'
});
• Set a DC in route()
data: function() {
var currentUser = Meteor.userId();
return Dossiers.find({id_user:
currentUser});
},
• Load subscriptions
waitOn: function(){
return Meteor.subscribe('dossiers');
}
42/56
43. Hook for checking before routing
• Use the onBeforeAction hook
Router.route('/list/:_id', {
name: 'listPage',
template: 'listPage',
onBeforeAction: function(){
var currentUser = Meteor.userId();
if ( currentUser ) {
this.next();
} else {
this.render('login');
}
}
});
43/56
49. Import from npm/atmosphere packages
• default import from npm
import moment from 'moment';
• named import from Atmosphere
import { HTTP } from 'meteor/http';
• Importing Meteor “pseudo-globals”
import { Name } from 'meteor/package‘;
import { Meteor } from 'meteor/meteor';
import { EJSON } from 'meteor/ejson'
49/56
50. Installing & using npm packages
• install a package into your app
meteor npm install --save package_name
• use a npm package from a file in your app, you simply import the name of the
package, this imports the default export from the package into the symbol
package
import package from 'package_name';
• you can also import specific functions from a package using the destructuring
syntax
import { isArray } from 'lodash';
• you can also import other files or JS entry points from a package
import { parse } from 'graphql/language';
50/56
51. Installing & using Atmosphere packages
• install an Atmosphere package
meteor add kadira:flow-router
• use an Atmosphere package, you can import it with the meteor/
prefix
import { SimpleSchema } from 'meteor/aldeed:simple-schema';
51/56
53. Command line toolmeteor create <name>
Make a subdirectory called <name> and create a new Meteor app there.
meteor run
Serve the current app at http://localhost:3000 using Meteor's local development server.
meteor debug
Run the project with Node Inspector attached, so that you can step through your server code line by line.
See meteor debug in the full docs for more information.
meteor deploy <site>
Bundle your app and deploy it to <site>.
Meteor provides free hosting if you deploy to <your app>.meteor.com as long as <your app> is a name that has not been claimed by someone else.
meteor update
Update your Meteor installation to the latest released version and then (if meteor update was run from an app directory)
update the packages used by the current app to the latest versions that are compatible with all other packages used by the app.
meteor add
Add a package (or multiple packages) to your Meteor project. To query for available packages, use the meteor search command.
meteor remove
Remove a package previously added to your Meteor project.
For a list of the packages that your application is currently using, use the meteor list command.
meteor mongo
Opens a MongoDB shell for viewing and/or manipulating collections stored in the database.
Note that you must already be running a server for the current app (in another terminal window) in order for meteor mongo to connect to the
app's database.
meteor reset
Reset the current project to a fresh state. Removes all local data. 53/56
54. Names and IDs
• HTML
• name
• must be unique within one <form>
only
• used by <form> controls such as
<input> and <select>
• used by GET and POST calls
• value
• content of name
• type
• CSS and JS
• id
• unique
• used by # in URLs and events
• used by the DOM
• class
• not unique
• used by . in events
• element can have many classes
• used by the DOM
54/56
55. Javascript objects
• unordered collection of properties
• each property is a (name, value) pair
• a name must be a unique string (inside the object)
• property attributes
• writable : can be set
• enumerable : property name is returned by a for/in loop
• configurable : can be deleted
• object attributes
• prototype : is a reference to another object from which
properties are inherited
• class : is a string that categorizes the type of an object
• the extensible flag specifies (in ECMAScript 5) whether
new properties may be added to the object
• var y = x // by reference, not by copy!
• A native object is an object or class of objects
defined by the ECMAScript specification
• Arrays, functions, dates, and regular expressions (for
example) are native objects
• A host object is an object defined by the host
environment (such as a web browser) within which
the JavaScript interpreter is embedded
• The HTMLElement objects that represent the structure
of a web page in client-side JavaScript are host objects
• Host objects may also be native objects, as when the
host environment defines methods that are normal
JavaScript Function objects
• A user-defined object is any object created by the
execution of JavaScript code.
• An own property is a property defined directly on
an object
• An inherited property is a property defined by an
object’s prototype object
55/56
56. Arrow functions
• An arrow function expression has a shorter syntax compared to function expressions and lexically binds the
this value (does not bind its own this, arguments, super, or new.target)
• Arrow functions are always anonymous
(param1, param2, …, paramN) => { statements }
(param1, param2, …, paramN) => expression
• equivalent to: => { return expression; }
• Parentheses are optional when there's only one parameter
(singleParam) => { statements }
singleParam => { statements }
• A function with no parameters requires parentheses
() => { statements }
56/56