2
\$\begingroup\$

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([
 '$compileProvider',
 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')
 continue;
 // 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)
 continue;
 // 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

200_success
145k22 gold badges190 silver badges478 bronze badges
asked Sep 22, 2018 at 18:15
\$\endgroup\$
0

0

Know someone who can answer? Share a link to this question via email, Twitter, or Facebook.

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.