Bringing the simplicity of Attributes/Annotations into Angular 1.X

28 בספטמבר 2015


One of the more interesting features of Angular 2 is its improved dependency injection mechanism

Unlike Angular 1.X you don't need to specify the dependencies manually in order to preserve minification capabilities

Angular 2 is smart enough to use the type information of the dependency and inject the correct implementation at run time

Can we do the same with Angular 1.X ? Sure, keep reading …

First lets describe the way we define a controller

import {MyApp} from '../App';
import {Controller} from '../Common/Decorators';
import {Contact, ContactService} from '../Services/ContactService';
@Controller(MyApp, "HomeCtrl")
class HomeCtrl {
    contacts: Contact[];
    constructor(contactService: ContactService) {
        contactService.getAll().then(contacts => {
            this.contacts = contacts;

And the service dependency

import {MyApp} from '../App';
import {Service, Inject} from '../Common/Decorators';
@Service(MyApp, "contactService")
export class ContactService {
    constructor(@Inject("$http"private $http: ng.IHttpService) {
    getAll(): ng.IPromise<Contact[]> {
        return this.$http.get("/contacts.json").then(response =>;
export interface Contact {
    id: number;
    name: string;

Second we need to define the Controller and Service decorators (A.K.A attribute/annotation)

export function Controller(module: ng.IModule, name: string) {
    return function (target: Function) {
        Reflect.defineMetadata("controller", target, { controllerName: name });
        module.controller(name, target);
export function Service(module: ng.IModule, name: string) {
    return function (target: Function) {
        Reflect.defineMetadata("service", { serviceName: name }, target);
        module.service(name, target);

For more information on ES7 decorators read hereReflect.defineMetadata is part of the ES7 reflection API. I am using this polyfill

The interesting implementation reside inside the set$inject function which fills Angular's $inject metadata with all correct dependencies

function set$inject(target) {
    var paramtypes: any[] = Reflect.getMetadata("design:paramtypes", target);
    var $inject = [
    paramtypes.forEach((type, index) => {
        var parameterName = null;
        var metadata;
        if (metadata = Reflect.getMetadata("service"type)) {
            parameterName = metadata.serviceName;
        else {
            throw new Error("Failed to resolve dependency: " + type);
    target.$inject = $inject;

We use Reflect.getMetadata API and extract all parameter types from the constructor. For each parameter type we check if it is a registered service and extract its name

We can extend that solution and support Angular 1.X components and other injectables. A nice component declaration may look like below

import {MyApp} from '../App';
import {Component, Inject} from '../Common/Decorators';
@Component(MyApp, "clock", {
    templateUrl: "/Scripts/Components/Clock.html",
class ClockComponent {
    time: Date;
    constructor( @Inject("$interval") $interval) {
        this.time = new Date();
        $interval(() => {
            this.time = new Date();
        }, 1000);

If you are interested with the full solution then contact me through my e-mail


Add comment
facebook linkedin twitter email

Leave a Reply

Your email address will not be published.

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>