I wrote a small module in typescript that augments the angularjs registerComponent function to provide a new way of default values for the component controller.

This module was written to solve the problem of not having a nice non-biolerplatey way of providing default values for components. Another problem it attempts to solve is to prevent the default value not applying if a value was provided trough bindings but the value is undefined or null.

The module works by using a static property on the component controller called $defaults. Getter functions are also supported to provide dynamic defaults for each component instance.

I wrote it with dynamic getters in mind. Because it is a function you could do anything in the function body (for example call an API).

I am looking for some feedback on the code and its purpose. The source code is available.

(function() {
type Dict<T = any> = { [key: number]: T, [key: string]: T };

angular.module('ng-sane-defaults', []).config([
    function configure($compileProvider: angular.ICompileProvider) {
        // get the original `registerComponent` function
        const registerComponent = $compileProvider.component;

        // override the original function
        $compileProvider.component = component;

         * @param nameOrDict name or Dictionary of component names and their options
         * @param options options for the component if the first parameter is the name
        function component(this: angular.ICompileProvider, nameOrDict: string|Dict<angular.IComponentOptions>, options?: angular.IComponentOptions) {
            // make sure the function signature is correct, if not pass it trough to the original function to handle errors
            if (typeof nameOrDict === 'string' && typeof options !== 'object')
                return registerComponent.call(this, nameOrDict, options as any);
            if (typeof nameOrDict !== 'string' && typeof nameOrDict !== 'object')
                return registerComponent.call(this, nameOrDict, options as any);

            // create the dictionary call signature as it is easier to work with
            const components: Dict<angular.IComponentOptions> = (typeof nameOrDict === 'string') ? { [nameOrDict]: options! } : nameOrDict;

            for (const key in components) {
                const options = components[key];

                // check if it has a controller function
                if (typeof options.controller !== 'function')

                // check if it has a `static $defaults` property, use `getOwnPropertyNames` to check for a getter function without invoking it
                if (Object.getOwnPropertyNames(options.controller).indexOf('$defaults') === -1)

                // get the original `$onInit` function or undefined if there was none
                const onInit: Function|undefined = options.controller.prototype.$onInit;

                // patch the `$onInit` function
                options.controller.prototype.$onInit = function $onInit() {
                    const defaults = (options.controller as Dict).$defaults;

                    if (typeof defaults === 'object') {
                        for (const prop in defaults) {
                            if (this[prop] == null) {
                                this[prop] = defaults[prop];

                    // call the lifecycle hook if it existed
                    return (typeof onInit === 'function') ? onInit.call(this) : void 0;

            return registerComponent.call(this, components);

You can check this plunkr to see it in action


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.