AngularJS with Babel in SailsJS

Since I've been porting my long-term project from CoffeeScript to native JavaScript I thought it'd be a good idea to share how it's working now.

Assuming we've got a brand new SailsJS application, the first thing we need is to install grunt-babel and configure the task.

# Install the Grunt task
npm i grunt-babel --save-dev  
npm i babel-preset-es2015 --save-dev  

Create a new file in tasks/config/ called babel.js with the following contents:

# tasks/config/babel.js

module.exports = function(grunt) {  
  grunt.config.set('babel', {
    dev: {
      options: {
        presets: ['es2015']
      },
      files: [{
        expand: true,
        cwd: 'assets/js/',
        src: ['**/*.js', '!dependencies/**/*.js'],
        dest: '.tmp/public/js/',
        ext: '.js'
      }]
    }
  });

  grunt.loadNpmTasks('grunt-babel');
};

Open tasks/register/compileAssets.js and change coffee:dev to babel:dev (around line ~7).

That's it.
You can now use ES2015 JavaScript in your Sails assets. Your "future JavaScript" will be transformed by Babel so that most current browser can handle it.

What about AngularJS?

Having the features of ES6 makes developing Angular way more comfortable.

Controllers

Controllers can easily be implemented through classes now, for example:

class HelloController {  
  constructor() {
    this.message = 'Hello World';
  }
}

awesomeApp  
  .controller('HelloController', HelloController);

While accessing class members like this:

<div ng-controller="HelloController as HelloCtrl">  
  {{ HelloCtrl.message }}
</div>  

See here for additional information about why using controller As ctrl and not using $scope.

Controllers and dependency injection

You may have some dependencies for your controllers. They're automatically injected by Angular, for example:

class HelloController {  
  constructor($element) {
    this.message = 'Hello World';
    console.log($element);
  }
}

If you want to use your dependencies in other methods of your class simply bind them to this:

class HelloController {  
  constructor($element) {
    this.message = 'Hello World';
    this.$element = $element;

    this.doStuff();
  }

  doStuff() {
    console.log(this.$element);
  }
}

Note: Probably not the most elegant solution. If someone has a better one feel free to tell me.

Services

Basically the same as for controllers:

class GreetingsService {  
  greet() {
    console.log('Hello!');
  }
}

awesomeApp  
  .factory('GreetingsService ', GreetingsService);

Used like this:

class HelloController {  
  constructor($element, GreetingsService) {
    this.message = 'Hello World';
    GreetingsService.greet();
  }
}

Directives

Even directives are that simple:

class DoStuff {  
  constructor() {
    this.restrict = 'E';
  }

  template() {
    return 'Hey {{name}}';
  }

  link(scope, elem, attrs) {
    scope.name = 'Bob';
  }
}

awesomeApp  
  .directive('doStuff', DoStuff);