Pages

Saturday, April 23, 2016

Learning Meteor.js [Part 3]: Let's get something on the screen

For meteor new comers this post will give you a feel for how a 'hello world' demo looks like. Coming from ASP.NET MVC myself, I will draw analogies between both worlds. Future post will not be as descriptive as this one.

Remove the 'cruft' packages
First, remove the 'insecure' and 'autopublish' packages, I don't think it is a good idea to keep them even when starting a project. In my opinion they lead you to the pit of failure.

meteor remove insecure
meteor remove autopublish

Add the packages that we need
Next, add router and a view engine. They are not required, but if you have experience with any MVC framework you'll feel more at home by getting a router from the beginning.

meteor add kadira:flow-router
meteor add kadira:blaze-layout

Setup the router
Now you can write the router:

import { FlowRouter } from 'meteor/kadira:flow-router';
import { BlazeLayout } from 'meteor/kadira:blaze-layout';

import '../../ui/app-body.js';

FlowRouter.route('/', {
    name: 'App_body',
    action() {
        BlazeLayout.render('App_body');
    }
});

Even if you know nothing of meteor, you should be able to infer what is happening here. You can see that meteor supports import/export of modules (new in version 1.3), you can see how a route is defined and how to render a view. Not so obvious is how we have to import the actual view file (app-body.js) since they also live in modules and all modules have to be explicitly imported.

Setup the view 'code behind'
Now, the view file that was imported, we have:

import { Meteor } from 'meteor/meteor'
import { Ingredients } from '../api/ingredients/ingredients.js';

import './app-body.html';
import './app-body.css';

Template.App_body.onCreated(function appBodyOnCreated() {
    Meteor.subscribe('ingredients');
});

Template.App_body.helpers({
    ingredients() {
        return Ingredients.find();
    }
});


Notice how this file imports the html and the css files. Feels like a convention should exist, but declaring as imports all the files needed to render the view makes it easy to follow all dependencies of the view. You can see that when the view is created it subscribes to the 'ingredients' collection. Think of this as the view requesting the ingredients from the server. Lastly, think of the helpers as the viewModel for the view, which exposes the ingredients to the HTML itself.


Setup the view
The view is just HTML with handlebars syntax. Keep in mind that meteor supports several view engines, in my case I chose the 'blaze' view engine.

{{#each ingredients}}
   <li class="list-group-item">{{name}}</li>
{{/each}}

Setup the server
The last step is to enable the server to 'publish' the ingredients collection that the view subscribes to:

const Ingredients = new Mongo.Collection('ingredients');

Meteor.publish('ingredients', () => {
   return Ingredients.find();
});

I simplified the code here, but in summary you create a Mongo collection and you publish a cursor so that the client can get the data.

Run and admire
That's it. You have a server that publishes data, a router that renders a view, a view model that subscribe to the data and sets up a view model and a view that renders HTML for the data. The magic is that the Ingredients collection can be accessed by both the client and by the server, including any methods that you define in it. O_O

Follow along
If you want to play with the code up to now use this tag: https://bitbucket.org/farmas/lunch-time/src/master/?at=v0.1

What's next?
Let's deploy this thing...


3 comments:

  1. by the way , I just created a lib folder , added route.js in it , and inside route.js started declaring routes without importing anything like

    "import { FlowRouter } from 'meteor/kadira:flow-router';" not needed

    "import { BlazeLayout } from 'meteor/kadira:blaze-layout';" not needed

    ReplyDelete
  2. I use Flow and Blaze too

    ReplyDelete
  3. The import feature was introduced on v1.3 and it only applies to files whithin the 'imports' folder. My understanding is that any file outside of this directory continues to work as before, where everything was exposed by global variables.

    ReplyDelete

Note: Only a member of this blog may post a comment.