Skip to content

Commit

Permalink
feat(core/directives): support one way binding for components by using
Browse files Browse the repository at this point in the history
…@input('<')

- directives are using one way binding by default

Closes #54
  • Loading branch information
Hotell committed Apr 2, 2016
1 parent 709637e commit 5f1dd82
Show file tree
Hide file tree
Showing 3 changed files with 117 additions and 41 deletions.
57 changes: 19 additions & 38 deletions src/core/directives/directive_provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,14 @@ import {
ContentChildMetadata,
ContentChildrenMetadata
} from './metadata_di';
import { _resolveChildrenFactory, _getParentCheckNotifiers, directiveControllerFactory } from './util/util';
import {
_resolveChildrenFactory,
_getParentCheckNotifiers,
directiveControllerFactory,
_extractBindings,
_parseIsolateBindings,
ParsedBindingValue
} from './util/util';

export type HostBindingsProcessed = {
classes: StringMap,
Expand Down Expand Up @@ -211,16 +218,7 @@ export class DirectiveProvider {
outputs: string[] = []
): StringMap {

const inputsBindings = _extractBindings( inputs, '=' );
const attrsBindings = _extractBindings( attrs, '@' );
const outputsBindings = _extractBindings( outputs, '&' );

return assign(
{},
inputsBindings,
attrsBindings,
outputsBindings
);
return _extractBindings( { inputs, outputs, attrs } );

}

Expand Down Expand Up @@ -709,7 +707,7 @@ export function _getHostListenerCbParams( event: any, eventParams: string[] ): a
}

/**
*
* Create Bindings manually for both Directive/Component
* @param scope
* @param attributes
* @param ctrl
Expand All @@ -733,13 +731,16 @@ export function _createDirectiveBindings(
BOOLEAN_ATTR[value.toLocaleLowerCase()] = value;
});*/

const {inputs=[],outputs=[],attrs=[]} = metadata;
const { inputs=[], outputs=[], attrs=[] } = metadata;
const parsedBindings = _parseIsolateBindings( { inputs, outputs, attrs } );
const _internalWatchers = [];
const _internalObservers = [];


// setup @Inputs
StringMapWrapper.forEach( _extractBindings( inputs ), ( alias: string, propName: string )=> {
StringMapWrapper.forEach( parsedBindings.inputs, ( config: ParsedBindingValue, propName: string ) => {

const { alias, optional, mode } = config;
const attrName = alias || propName;

if (!Object.hasOwnProperty.call(attributes, attrName)) {
Expand All @@ -761,8 +762,9 @@ export function _createDirectiveBindings(
} );

// setup @Outputs
StringMapWrapper.forEach( _extractBindings( outputs ), ( alias: string, propName: string )=> {
StringMapWrapper.forEach( parsedBindings.outputs , ( config: ParsedBindingValue, propName: string )=> {

const { alias, optional, mode } = config;
const attrName = alias || propName;

// Don't assign Object.prototype method to scope
Expand All @@ -780,8 +782,9 @@ export function _createDirectiveBindings(
} );

// setup @Attrs
StringMapWrapper.forEach( _extractBindings( attrs ), ( alias: string, propName: string )=> {
StringMapWrapper.forEach( parsedBindings.attrs, ( config: ParsedBindingValue, propName: string )=> {

const { alias, optional, mode } = config;
const attrName = alias || propName;
let lastValue;

Expand Down Expand Up @@ -821,28 +824,6 @@ export function _createDirectiveBindings(

}

/**
*
* @param bindings
* @param typeSymbol
* @param SPLIT_BY
* @returns {StringMap}
* @internal
* @private
*/
export function _extractBindings( bindings: string[], typeSymbol: string = '', SPLIT_BY = ':' ): StringMap {

return bindings.reduce( ( acc, binding: string )=> {

const [name,alias=''] = binding.split( SPLIT_BY ).map( part=>part.trim() );
acc[ name ] = `${ typeSymbol }${ alias }`;

return acc;

}, {} as StringMap );

}


/**
* setups watchers for children component/directives provided by @Query decorators
Expand Down
89 changes: 89 additions & 0 deletions src/core/directives/util/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -420,3 +420,92 @@ export function createNewInjectablesToMatchLocalDi(
export function isAttrDirective( metadata ): boolean {
return metadata instanceof DirectiveMetadata && !(metadata instanceof ComponentMetadata);
}


/**
* returns angular 1 bindToController Map
* ```js
* { property: '=', onEvent: '&', attrVal: '@', oneWay: '<' }
* ```
* @returns {StringMap}
* @internal
* @private
*/
export function _extractBindings(
{
inputs=[],
outputs=[],
attrs=[]
}: {
inputs?: string[],
outputs?: string[],
attrs?: string[]
}={}
): StringMap {

const parsedBindings = _parseIsolateBindings( { inputs, outputs, attrs } );

return StringMapWrapper
.values( parsedBindings )
.reduce( ( acc, bindingMap: ParsedBindingsMap ) => {

StringMapWrapper.forEach( bindingMap, ( config: ParsedBindingValue, name: string ) => {
const optionalSymbol = config.optional
? '?'
: '';
acc[ name ] = `${ config.mode }${ optionalSymbol }${ config.alias }`;
} );

return acc;
}, {} as StringMap );

}

export type ParsedBindingValue = { mode: string, alias: string, optional: boolean}
export type ParsedBindingsMap = {[name:string]:ParsedBindingValue};
export type ParsedBindings = {
inputs: ParsedBindingsMap,
outputs: ParsedBindingsMap,
attrs: ParsedBindingsMap,
[key: string]: ParsedBindingsMap
};


/**
* parses input/output/attrs string arrays from metadata fro further processing
* @param inputs
* @param outputs
* @param attrs
* @returns {{inputs: ParsedBindingsMap, outputs: ParsedBindingsMap, attrs: ParsedBindingsMap}}
* @private
*/
export function _parseIsolateBindings({ inputs=[], outputs=[], attrs=[] }): ParsedBindings{

const INPUT_MODE_REGEX = /^(<|=)?(\??)(\w*)$/;
const SPLIT_BY = ':';

return {
inputs: _parse( inputs, '=' ),
outputs: _parse( outputs, '&' ),
attrs: _parse( attrs, '@' )
};

function _parse( bindingArr: string[], defaultMode: string ): ParsedBindingsMap {

return bindingArr.reduce( ( acc, binding: string )=> {

const [name,modeConfigAndAlias=''] = binding.split( SPLIT_BY ).map( part=>part.trim() );

const [, mode=defaultMode, optional='', alias=''] = modeConfigAndAlias.match( INPUT_MODE_REGEX ) || [];

acc[ name ] = {
mode,
alias,
optional: optional === '?'
};

return acc;

}, {} as StringMap );
}
}
12 changes: 9 additions & 3 deletions test/core/directives/directive_provider.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -625,7 +625,11 @@ describe( `directives/directive_provider`, ()=> {

it( `should create bindings from inputs,attrs,outputs`, ()=> {

const inputs = [ 'one', 'two: twoAlias', 'oneOpt: ?oneOpt' ];
const inputs = [
'one', 'two: twoAlias',
'oneOpt: ?oneOpt',
'oneWay: <', 'oneWayAlias: <oneWayAlas'
];
const attrs = [ 'color', 'brood: broodAlias' ];
const outputs = [ 'onFoo', 'onMoo: onMooAlias' ];

Expand All @@ -637,9 +641,11 @@ describe( `directives/directive_provider`, ()=> {
color: '@',
brood: '@broodAlias',
onFoo: '&',
onMoo: '&onMooAlias'
onMoo: '&onMooAlias',
oneWay: '<',
oneWayAlias: '<oneWayAlas'
};

expect( actual ).to.deep.equal( expected );

} );
Expand Down

0 comments on commit 5f1dd82

Please sign in to comment.