Joshua Soileau
Joshua Soileau

Reputation: 3015

Meteor.js/Handlebars.js - Understanding procedural coding styles & scoping

I'm using the Meteor.js framework for the first time and I'm having trouble understand the order of events of the templating system (never used Handlebars.js), as well as how scoping is handled.

I have a file called audio.js. In it, I define a class and init a variable with that class:

// Question about this as well, how do I properly make a jQuery class?
// Is this the right way?
$.Audio = function() {}

$.Audio.prototype = {
  init: function() {
      this.ele = $('.blahblah');
  }
  startAudio: function() {
      // do things
  }
}

var Music = new $.Audio();

So my var Music is created inside of audio.js.

Now, in another js file, I'm doing some templating functions:

Template.bars.rendered = function {
    Music.startAudio();
}

But I get a Uncaught ReferenceError: Music is not defined from that line.

Main question:

How does scoping work in Meteor.js? How can I reference my Music variable that I declared in one file inside my Template function in another file?

Less important question, which might not easily be answered because it's not a very good question. How do I procedurally write javascript with meteor? This is the first time I've worked with templating. I am used to javascript being rendered as it is listed in the DOM (or as the DOM is loaded or events are fired using listeners, etc). I don't understand how to tie together a logical chain of events in javascript using templates.

Upvotes: 1

Views: 291

Answers (1)

sbking
sbking

Reputation: 7680

From the Meteor docs:

  • Files in directories named lib are loaded first.

  • Files that match main.* are loaded after everything else.

  • Files in subdirectories are loaded before files in parent directories, so that files in the deepest subdirectory are loaded first (after lib), and files in the root directory are loaded last (other than main.*).

  • Within a directory, files are loaded in alphabetical order by filename.

Also, here's a bit from the docs about exporting variables:

// File Scope. This variable will be visible only inside this
// one file. Other files in this app or package won't see it.
var alicePerson = {name: "alice"};

// Package Scope. This variable is visible to every file inside
// of this package or app. The difference is that 'var' is
// omitted.
bobPerson = {name: "bob"};

So if you want your music var to be available in other files, do the following:

  • Put your audio.js file in a lib folder, like lib/audio.js or client/lib/audio.js. This will ensure that it is loaded before other files.

  • Do not declare your music variable with the var keyword. Just do music = new $.Audio(); This will attach music to the global scope, allowing files that are loaded later to access it.

Why is that necessary? Meteor wraps all of your files in an IIFE. So, for example, if your file looks like this:

var MyClass = function() {};
var myInstance = new MyClass();

Then Meteor will wrap that file like this:

(function() {
  var MyClass = function() {};
  var myInstance = new MyClass();
})();

Now the vars are not available to other files, because of JavaScript's function scoping. Variables declared without var are attached to the global scope, regardless of what functions they may be enclosed inside.

Less important question, which might not easily be answered because it's not a very good question. How do I procedurally write javascript with meteor? This is the first time I've worked with templating. I am used to javascript being rendered as it is listed in the DOM (or as the DOM is loaded or events are fired using listeners, etc). I don't understand how to tie together a logical chain of events in javascript using templates.

Go read the docs. You can access them at http://docs.meteor.com/. Read every single line - it will answer many questions like this you might have. In short, you can define event handler functions on templates, which will be triggered when events occur on the HTML elements inside the template. You can also define helper functions on the templates, which can rely on reactive data sources, and will be automatically re-run when those reactive data sources change (which will then cause the template to be re-rendered). This is covered in the Templates section of the Meteor docs.

The idea is this: your templates define the structure of the HTML that should be rendered for your app. This HTML is driven by reactive data sources, and is re-rendered every time the reactive data source changes. This ensures your HTML is always synchronized with your data, and yet you don't have to write any custom DOM manipulation code! So, for a simple example of the order of execution:

  1. A reactive data source (for example, Session, a Meteor.Collection, or your own reactive data source using Deps) is created with an initial value.

  2. A template helper function that depends on your data source is executed with the initial value of the data source.

  3. The template is rendered using the results of the helper function, which is included in the template like {{myHelper}}. Template event handlers are attached to the resulting HTML DOM automatically.

  4. An event is triggered on the DOM, such as clicking on a button.

  5. The event handler is run. Perhaps that event handler changes the reactive data source.

  6. The helper function sees that the data source has changed, and is automatically re-run.

  7. The relevant parts of the template are automatically re-rendered, using the new value from the helper function.

Upvotes: 2

Related Questions