Last active
August 29, 2015 14:16
-
-
Save danharper/0ce7298d14b569ac3aa3 to your computer and use it in GitHub Desktop.
ngBridge - wrap your Angular modules to support ES6 classes, and stricter assurances of DI
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
export function ngBridged(name, deps) { | |
return ngBridge(angular.module(name, deps)) | |
} | |
export function ngBridge(ngModule) { | |
const register = (type, ...args) => ngBridge(ngModule[type](...args)) | |
const injectable = type => (name, injectableFunc) => register(type, name, ngInject(injectableFunc)) | |
const pass = type => (...args) => register(type, ...args) | |
return { | |
component: (...args) => register('directive', ...ngComponent(...args)), | |
directive: (...args) => this.component(...args), | |
controller: injectable('controller'), | |
service: injectable('service'), | |
factory: injectable('factory'), | |
provider: injectable('provider'), | |
filter: injectable('filter'), | |
animation: injectable('animation'), | |
config: pass('config'), | |
run: pass('run'), | |
value: pass('value'), | |
constant: pass('constant'), | |
routes: router => register('config', ['$stateProvider', $sp => router($sp.state)]) | |
} | |
} | |
export function ngClass(injectableClass) { | |
return [...getInjects(injectableClass), (...injectedArgs) => new injectableClass(...injectedArgs)] | |
} | |
export function ngInject(injectableFunc) { | |
if (Array.isArray(injectableFunc)) { | |
return injectableFunc | |
} | |
else { | |
return [...getInjects(injectableFunc), injectableFunc] | |
} | |
} | |
export function ngComponent(name, component = null) { | |
if ( ! component) return ngComponent(null, name) | |
const ddo = component.ddo() | |
const directive = () => { | |
return { | |
...ddo, | |
scope: ddo.bind, | |
bindToController: true, | |
controller: ngInject(component), | |
controllerAs: ddo.name | |
} | |
} | |
return [(name || ddo.name), directive] | |
} | |
function getInjects(func) { | |
return func.ngInject ? func.ngInject() : [] | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Modules | |
//////////////////////////////////// | |
// you can full on replace the angular.module call: | |
import {ngBridged} from 'ngBridge' | |
ngBridged('my.module.name', []) | |
// or wrap your module: | |
import {ngBridge} from 'ngBridge' | |
ngBridge(angular.module('my.module.name', [])) | |
// Controllers | |
//////////////////////////////////// | |
// an injectable ES6 controller: | |
class BooksListController { | |
// define dependencies in static ngInject methods, instead of the $inject property or array syntax | |
static ngInject() { | |
return ['$http'] | |
} | |
constructor($http) { | |
} | |
} | |
// registering on your module: | |
.controller('BooksListController', BooksListController) // on an ngBridge-wrapped module | |
.controller('BooksListController', ngInject(BooksListController)) // on non-wrapped module | |
// Components (Directives) | |
//////////////////////////////////// | |
// a new directive (you can also use ngInject on here) | |
class BookComponent { | |
static ddo() { | |
return { | |
name: 'book', // name inside template & external name (<book></book>) | |
bind: { | |
title: '@' | |
}, | |
template: `<strong>Name: {{book.title}}</strong> | |
<button ng-click="book.share()">Share!</button>` | |
} | |
} | |
share() { | |
alert(`Sharing book titled ${this.title}`) | |
} | |
} | |
// registering on your module: | |
.component(BookComponent) // registering with self-assigned name | |
.component('movie', BookComponent) // registering named <movie></movie> instead | |
.directive(...ngComponent(BookComponent)) // on a non-wrapped module | |
.directive(...ngComponent('movie', BookComponent)) // on a non-wrapped module, naming as <movie></movie> | |
// Services etc. | |
//////////////////////////////////// | |
class MyService { | |
static ngInject() { | |
return ['$http'] | |
} | |
constructor(thisisHttp) { | |
} | |
doSomething() { | |
} | |
} | |
// registering on your module: | |
.service('myService', MyService) | |
.service('myService', ngInject(MyService)) // non-wrapped module | |
// this still works: | |
.service('myService', ['$http', $http => { | |
// ... | |
}]) | |
// but this won't (we're enforcing named DI) | |
.service('myService', $http => { | |
// $http is undefined | |
}) | |
// Classes for config/run etc.? sure! | |
//////////////////////////////////// | |
class DoSomethingForConfig { | |
static ngInject() { | |
return ['$stateProvider'] | |
} | |
constructor($stateProvider) { | |
// ... | |
} | |
} | |
// registering: | |
.config(ngClass(DoSomethingForConfig)) // works either wrapped or not | |
// Routing (only included in this preview, it's the UI Router) | |
//////////////////////////////////// | |
.router(state => { | |
state('home', { | |
url: '/', | |
template: 'Hello, World!' | |
}) | |
}) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment