Last active
October 24, 2016 10:51
-
-
Save ghetolay/b1ed92138ef17562789896208aee1d56 to your computer and use it in GitHub Desktop.
Custom decorator to extend Angular 2 component
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
//Example of a custom decorator | |
import { forwardRef } from '@angular/core'; | |
import { NG_VALUE_ACCESSOR } from '@angular/forms'; | |
import { ExtendsComponent, ExtendsComponentMetadata } from './extendscomponent'; | |
export var DatePicker = function( metadata: ExtendsComponentMetadata ): (cls: any) => any { | |
return (target: Function) => { | |
metadata.providers = metadata.providers || []; | |
metadata.providers.push({ | |
provide: NG_VALUE_ACCESSOR, | |
useExisting: forwardRef(() => target), | |
multi: true | |
}); | |
return ExtendsComponent(metadata)(target); | |
}; | |
}; |
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
//only work for JIT not AOT | |
//That's why it's just partial code, maybe someday this will be usefull and will finish it. | |
import { Component, Provider, isDevMode } from '@angular/core'; | |
export interface ExtendsComponentMetadata { | |
selector?: string; | |
template?: string; | |
templateUrl?: string; | |
styles?: string[]; | |
styleUrls?: string[]; | |
providers?: Provider[]; | |
append?: { | |
styles?: string[]; | |
styleUrls?: string[]; | |
providers?: Provider[]; | |
}; | |
//TODO | |
//remove?: Component; | |
//reduce?: { | |
// styles, styleUrls, providers | |
//} | |
} | |
export function ExtendsComponent( componentMetadata: ExtendsComponentMetadata ): (cls: any) => any { | |
return function (target: Function) { | |
let metadata: Component = {}; | |
let metas: (ExtendsComponentMetadata | Component)[] = [ componentMetadata ]; | |
//find all metadatas across parents | |
let parentTarget = target; | |
do { | |
parentTarget = Object.getPrototypeOf(parentTarget.prototype).constructor; | |
let parentAnnot = Reflect.getMetadata('annotations', parentTarget); | |
if (parentAnnot) { | |
if (! (parentAnnot instanceof Array) ) { | |
//dunno what getMedata() can return just throw until we found a case | |
if (isDevMode) throw 'annotations not an array : ' + parentAnnot; | |
else continue; | |
} | |
for ( let annotation of parentAnnot ) { | |
/* | |
TODO if it's ExtendsComponent | |
*/ | |
if (annotation instanceof Component) | |
metas.push(annotation); | |
} | |
} | |
} while ( parentTarget !== Object); | |
// loop from last to first | |
for ( let i = metas.length - 1; i >= 0; i--) | |
extendsMetadata(metadata, metas[i]); | |
return Component(metadata)(target); | |
}; | |
} | |
function extendsMetadata(source: Component, target: (ExtendsComponentMetadata | Component)) { | |
for (let prop in target) { | |
let targetValue = target[prop]; | |
if ( isBlank(targetValue) ) | |
continue; | |
if (prop === 'append') { | |
for ( let appendProp in targetValue) | |
source[appendProp] = [...source[appendProp], targetValue[appendProp]]; | |
} | |
else | |
source[prop] = targetValue; | |
}; | |
} | |
//same func used on angular 2, dunno why they don't export it | |
function isBlank(v) { | |
return v === undefined || v === null; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment