Now, we talk about their conflicts

Here is a list of things that I found Meteor and AngularJS don’t like each other about or don’t agree on:

Script load order (namely, when angular.js is loaded) Bootstrapping of ngApp Loading of Angular template files, and template delimiter {{…}} Declaration and usage of Meteor collections Code minification

Before walking through each of this list together, I want to also briefly list my solutions to the problems (and you can skip the rest if you don’t care for technical details):

Follow a runlevel-like convention of organizing files. Instead of using ng-app on <html> or <body>, use it on a page container <div>. Change Angular template delimiter to something else, organize template files under Meteor’s convention, and load all templates from Meteor’s Template at start. Declare Meteor collections at global scope, create a wrapping function around Meteor’s Deps.autorun for data binding. Follow Angular’s dependency injection convention on EVERY occasion.

Now let’s look at these conflicts one by one.

Load order

This is rather a Meteor problem than a conflict, but needs to be sorted out first. Currently, Meteor has an awkward convention of Javascript files load order: it concatenates all your .js files under project directory and load them before anything when your actual page loads. The order during concatenation depends on file names and their directory depths.

I used the approach of following a runlevel-like conventions for placing script files: all client side .js files are placed under /client; library files are placed under /client/lib; libraries that must be loaded before others are placed under numbered directories such as /client/lib/00_angular, /client/lib/01_jquery-ui, /client/lib/01_codemirror, etc.

This approach is very straightforward, but might feel a bit hackish. There’s another approach that is to use a Meteorite package containing the angular.js file. However, there is currently no such Meteorite package that provides updated angular.js file (you really only need this one file, pre-loading any other angular files is unnecessary and only decreases its flexibility). Creating your own package, however, is not hard, and actually works with Bower.

Bootstrapping Angular

Angular apps need to be bootstrapped by either including an ng-app attribute at a root node, or manually through code. However, Meteor currently errors if you use <html> tag or <body> tag with extra attributes. The solution to this is very simple: instead of doing this

<body ng-app="my-app">

...

</body>

Do this:

<body><div ng-app="my-app">

...

</div></body>

Angular template files

There are a few problems involved regarding template files. First, Meteor compiles all .html files (actually all your project files) and serve them indistinguishably to all requests, which makes retrieving a single template file impossible. Second, Meteor compiles .html files and change things between {{ and }} into code before serving them. Third, currently Meteor is tightly coupled with its UI engine and it’s very hard to change these behaviors.

My solution is inspired by ngMeteor, and is basically another structuring convention. I wrap each template files inside a HTML template block:

<template name="template_filename.html">

...

</template>

This makes Meteor save the contents of each template file into a property of Meteor’s Template object. Then, you can load these templates when Angular starts, and use them as usual for templateUrl:

Update for Meteor 0.8.0: Meteor now uses a new template engine, and has deprecated the render() method. Use the following code instead to load templates:

Then, we need to change Angular’s template delimiter, so that Meteor doesn’t try to compile them:

This solution has a very handy side effect: it makes manually loading/compiling Angular templates very simple since all templates are loaded already in template cache. This is particularly useful if you want to create recursive directives.

There’s also another less hackish solution to this: placing all templates under /public and treat them as static files. The problem with this approach is that Meteor aggressively caches static files, and this can create a lot of headaches during development.

Meteor Collection

Using Meteor Collection with AngularJS is the single reason that we want to use these two frameworks together: we want data synchronization from database views straight to the DOM. There isn’t much of a conflict concerning Meteor Collection and Angular, but rather, the question of how to use them efficiently.

During my experimentation with both frameworks, I’ve tried quite a few ways of using Meteor Collection. The conclusion I reached is to use them in a very Meteor fashion: define collections at global scope, and use Meteor’s reactive system to handle synchronization, namely Deps.autorun.

I wrapped Deps.autorun in the following Angular factory, to make sure Angular is notified when data synchronization occurs:

With the above function, we can now bind Meteor Collection to Angular scopes very easily:

Update (Oct 14, 2014): as @qinfeng pointed out, this data binding may choke on very large collections as Angular will re-render DOM for every item in the collection, regardless of whether they are changed, because they all have new object references. In this case (very large fetched collections), we need to reuse unchanged old items, so that they can pass Angular’s dirty check. Use the method below to bind Meteor collections instead:

Updated examples: recently I was often asked about using other Meteor classes, so I decided to add a few more examples below to show how this autorun wrapper can be used to achieve different goals. Note that you can use Meteor classes directly if they are non-reactive, autorun is only needed for reactivity. Read more on Meteor reactivity.

Example 1: using Meteor accounts

Example 2: using Meteor sessions

Example 3: using autorun with $scope.$watch

Code minification

This is rather an Angular gotcha than a problem, but magnified because of Meteor’s super easy deployment. AngularJS heavily relies on dependency injection (fancy Java word for runtime dependency resolution). If you don’t follow Angular’s best practice on declaring dependencies, it will break eventually.

When used with Meteor, Angular may run fine in development but fail to start in production. This is because once deployed, Meteor does all the heavy lifting of compiling and renaming asset files, meaning all .js files are minified. This can break if you use reflection based dependency declaration in Angular.

The correct way is to simply use the array notation, and it’s important to use it EVERYWHERE, including your controllers, directives, the controller function inside directives, configurations, services, factories, run scripts, and whatnot. Miss any one of those and you will get a very very hard to understand error message on your production site.