Skip to content

Instantly share code, notes, and snippets.

@xogeny
Created July 8, 2015 20:26
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save xogeny/fcbeba98b8d70dc5003a to your computer and use it in GitHub Desktop.
Save xogeny/fcbeba98b8d70dc5003a to your computer and use it in GitHub Desktop.
My canonical directive structure
/// <reference path="../typings/angularjs/angular.d.ts" />
// A canonical layout for defining angular directives in TypeScript
module ModuleForDirective {
// Defines what we expect to find in $scope. This mainly the stuff
// mapped in the scope: attribute of the directive, but it could
// include stuff inherited into $scope as well...
interface Scope extends ng.IScope {
// Stuff defined in { scope: { ... } } (attrs on directive)
// Stuff inherited in $scope
}
class Controller {
// View properties (stuff we compute from $scope)
// ...
static $inject = ["$scope", ...];
constructor(private $scope: Scope, ...) {
// Assign watches on stuff in { scope: { ... } }
$scope.$watch('prop1', (nv: TypeOfProp1) => {
this.computeView(nv, $scope.prop2)
}, true);
$scope.$watch('prop2', (nv: TypeOfProp2) => {
this.computeView($scope.prop1, nv)
}, true);
}
// Any methods you want to be able to invoke on the controller (from the template)
// (generally, these are to manipulate values on $scope are to evaluate
// computed properties.
// This method is used to recompute view properties based on values in $scope
// This assumes all members of the Controller class depend on all members in $scope.
// If they don't, then multiple functions can be defined to more efficiently compute
// subsets based on changes (dependencies) in $scope.
private computeView(prop1: TypeOfProp1, prop2: TypeOfProp2) {
// Update setup related view quantities
// (compute values of members of this class based on p1 and p2 from $scope)
// this._____ = f(prop1, prop2);
}
}
export function Directive(): ng.IDirective {
return {
restrict: "E", // Can only be an Element
replace: false,
controller: Controller,
controllerAs: "cname",
template: ...,
scope: {
prop1: '=',
prop2: '=',
...
// Should match inputs to Scope interface
},
// Fancy stuff often requires a link: field to be defined as well
};
}
Directive.$inject = []; // Any dependencies to inject in call to Directive
}
angular.module("ModuleName").directive(ModuleForDirective.Directive)
@basarat
Copy link

basarat commented Jul 8, 2015

I don't see anything bad here. Here's what we have at Picnic:

Filename fooDirective.ts

import {dustApp} from "../main";

export class FooDirectiveController {

    static $inject = ['$element', '$scope'];
    constructor(public $element: JQuery, public $scope: FooDirectiveScope) {
        $scope.vm = this;

        // Any Jquery access goes here. Use $element

        // Setup any $watch on $scope that you need
    }
}

export interface FooDirectiveScope extends ng.IScope {
    bar: string;

    // Local design only
    vm: FooDirectiveController;
}

dustApp.directives.directive('foo', function (): ng.IDirective {
    return {
        restrict: 'E',
        scope: {
            // NOTE : see documentation in type information
            bar: '='
        },
        templateUrl: 'fooDirective.html',
        controller: FooDirectiveController
    };
});

Filename fooDirective.html

<div>
    Foo
</div>

Note: I'm using external modules

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment