16 September 2015

Meteor

  • javascript on client and server
  • automatic updating of pages
  • eliminates need for REST apis
  • latency handling
  • self-contained application bundles

Technologies

  • Javascript
  • Node.js
  • MongoDb, replacable (eg mysql etc)
  • Handlebars, replacable ( eg Jade etc )

Packaging

own package system, not npm

Storage

layered mongo on client replicated to mongo on backend

Support

  • mac, officially
  • linux, officially
  • windows, unofficially

Install

win.meteor.com

MSI or exe

Create app

meteor create "project name" Run app

cd "project name"

meteor

How meteor works

mongodb

 
meteor server			<- initial request        BROWSER

        				<- web sockets connection
						<- communicate using DDP 

sockets or polling as fallback sock.js

publish/subscribe

meteor server <--- change data  clients
			  <--- subscribe
			  publish ---> 

rendering function creates document fragment. 1) Observer is being put on the data that 2) rerenders fragment when data change.

Create example apps

meteor create --example todos

DDP - distributed data protocol

  • publish/subscribe
  • remote procedure calls

Create first real meteor application

Let’s create our first app meteor app. Let’s call it avengers:

meteor create Avengers

Meteor has now scaffolded a project for us looking like this:

Avengers.css
Avengers.js
Avengers.html

Meteor uses a concept called templates to communicate between UI and js code. Example html:

<html>
	<body>
		
	</body>
</html>


<template name="hello">
  <button>Click Me</button>
  <p>You've pressed the button  times.</p>
</template>

As you can see the template called hello are referred to in the body tag with the following command

The js file can communicate with this snippet by defining two functions:

Template.templatename.helpers
Template.templatename.events

These functions needs to be invoked with an object. On respective object you specify what you need it to do.

Helpers function

The helpers function is used to store data that you can refer to into the template. Example implementation:

Template.hello.helpers({
counter: function () {
  return Session.get('counter');
}   });

Usage in template:

<template name="hello">
  <button>Click Me</button>
  <p>You've pressed the button  times.</p>
</template> By using  we can output the data in the template

Events function

The events function is used to keep track of all events and how to respond to them. Example implementation:

Template.hello.events({
	'click button': function () {
  	// increment the counter when button is clicked
  	Session.set('counter', Session.get('counter') + 1);
}   });

That’s it this is a very simple meteor program. But of course it’s not very useful without being able to talk to a backend.

A meteor program talking to a database

Meteor is a full stack framework writtern in javascript. The main idea is for it to have rapid application development and also to promote collaboration, more on that later.

Define a backend with a database

Meteor uses MongoDb as a database. And MongoDb uses collections rather than tables to store data. The concepts are similar. So let’s create a collection called Users. At the top of your Avengers.js file lets add the following row:

Users = new Meteor.Collection('users'); That's it that is we need to create a collection. We are not quite done though. We need to seed it with some data.

First we need to realize something and that is that we are mixing serverside code and client side code in the same file. Bit messy right? But for this small app it’s fine but let’s talk about architecture later.

if (Meteor.isServer) {

} With this line we are on serverside. What we want to do to seed data is to check that the collection *Users* is empty and if so add data to it, only if it is empty.

Meteor.startup(function () {	
	if(Users.find().count() === 0){
      Users.insert({
        name : 'karl',
        loggedIn : false
      });

      Users.insert({
        name : 'chris',
        loggedIn : false
      });
    } 
}

Full code so far

if (Meteor.isServer) {
	Meteor.startup(function () {	
		if(Users.find().count() === 0){
	      Users.insert({
	        name : 'karl',
	        loggedIn : false
	      });
	
	      Users.insert({
	        name : 'chris',
	        loggedIn : false
	      });
	    } 
	}
}

So we added some code to input some data. So how do we retrieve this data and show it in the template?

Retrieve data

Remember the helpers function, the one that stores our properties? That is where the call to the database needs to be made. So let’s do that

Template.userlist.helpers({
	users : function(){
		return Users.find();
	}
}); And to use it in template

<template name="userlist">
<h3>All users</h3>

<p>
	
	
</p>

</template>

CRUD application

Most apps that are created are either pure CRUD, Create Read Update Delete type ap/create superheroes

meteor create Superheroes
cd SuperHeroes
meteor
... a minute later your app should be up and running on localhost:3000

My suggestion is that you download the node http server called http-server

npm install http-server

Create

Let’s create a template region that supports adding a superhero, containing an input field and a button

<template name="addhero">
	<h3>Add hero</h3>
	<input type="text" id="newhero">
	<p>
		<button>Add</button>
	</p>
</template> Let's create the corresponding js code that support adding a hero

Template.addhero.events({
    'click button' : function(){
      var newhero = $('#newhero').val();
      Heroes.insert({ name : newhero });
    }
}); ### Read  We already know how to list data from database in a list but here it is:

<template name="superherolist">

<p>
	<input type="text" id= value= /> 
	<button id="edit">Save</button>
	<button id="delete">Delete</button>
</p>

</template>

As you can see this template supports some future operations we havn’t implemented yet like edit and delete.

Here is the corresponding js code:

Template.superherolist.helpers({
    heroes : function(){
      return Heroes.find();
    }
});

Update

The template code for the update is basically adding an updating button to the list view so what’s interesting here is the js code:

Template.superherolist.events({
  'click #edit' : function(){
    var newValue = $('#' + this._id).val();
    Heroes.update(this._id, { $set : { name : newValue } });
    console.log(this._id) // the entity to change
  }   }); So what we do here is retrieve the value and perform an update operation

Delete

As with the update the delete is just a button on the list view and corresponding js code is very very simple:

Template.superherolist.events({
  'click #edit' : function(){
    var newValue = $('#' + this._id).val();
    Heroes.update(this._id, { $set : { name : newValue } });
    console.log(this._id) // the entity to change
  },
  'click #delete': function(){
    Heroes.remove(this._id);
  }   });

'click #delete': function(){
    Heroes.remove(this._id);
  } ### Full code #### Template

<head>
  <title>SuperHeores</title>
</head>

<body>
  <h1>Welcome to Superhero factory</h1>

  <p>
  	
  </p>  

  <p>
  	
  </p>
</body>

<template name="addhero">
	<h3>Add hero</h3>
	<input type="text" id="newhero">
	<p>
		<button>Add</button>
	</p>
</template>

<template name="superherolist">
	
	<p>
		<input type="text" id= value= /> 
		<button id="edit">Save</button>
		<button id="delete">Delete</button>
	</p>
	
</template> #### js code

Heroes = new Meteor.Collection('heroes');

if (Meteor.isClient) {

  Template.superherolist.helpers({
    heroes : function(){
      return Heroes.find();
    }
  });

  Template.superherolist.events({
      'click #edit' : function(){
        var newValue = $('#' + this._id).val();
        Heroes.update(this._id, { $set : { name : newValue } });
        console.log(this._id) // the entity to change
      },
      'click #delete': function(){
        Heroes.remove(this._id);
      }
  });

  Template.addhero.events({
    'click button' : function(){
      var newhero = $('#newhero').val();
      Heroes.insert({ name : newhero });
    }
  });

  Template.hello.helpers({
    counter: function () {
      return Session.get('counter');
    }
  });
}

if (Meteor.isServer) {
  Meteor.startup(function () {

    // seed data
    if(Heroes.find().count() === 0){
      Heroes.insert({
        name : 'Thor'
      });

      Heroes.insert({
        name : 'Spiderman'
      });
    }
    // code to run on server at startup
  });
}


blog comments powered by Disqus