Skip to content
This repository has been archived by the owner on Feb 22, 2018. It is now read-only.

Commit

Permalink
feat(core): provide support to define the same selector on multiple d…
Browse files Browse the repository at this point in the history
…irectives
  • Loading branch information
matsko authored and mhevery committed Jan 24, 2014
1 parent e01d5fd commit dd35653
Show file tree
Hide file tree
Showing 7 changed files with 71 additions and 18 deletions.
6 changes: 3 additions & 3 deletions lib/core/directive.dart
Original file line number Diff line number Diff line change
Expand Up @@ -432,11 +432,11 @@ abstract class NgDetachAware {
}

@NgInjectableService()
class DirectiveMap extends AnnotationMap<NgAnnotation> {
class DirectiveMap extends AnnotationsMap<NgAnnotation> {
DirectiveMap(Injector injector, MetadataExtractor metadataExtractor,
FieldMetadataExtractor fieldMetadataExtractor)
: super(injector, metadataExtractor) {
Map<NgAnnotation, Type> directives = {};
Map<NgAnnotation, List<Type>> directives = {};
forEach((NgAnnotation annotation, Type type) {
var match;
var fieldMetadata = fieldMetadataExtractor(type);
Expand All @@ -452,7 +452,7 @@ class DirectiveMap extends AnnotationMap<NgAnnotation> {
});
annotation = annotation.cloneWithNewMap(newMap);
}
directives[annotation] = type;
directives.putIfAbsent(annotation, () => []).add(type);
});
_map.clear();
_map.addAll(directives);
Expand Down
46 changes: 41 additions & 5 deletions lib/core/registry.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,6 @@ abstract class AnnotationMap<K> {
var meta = extractMetadata(type)
.where((annotation) => annotation is K)
.forEach((annotation) {
if (_map.containsKey(annotation)) {
var annotationType = K;
throw "Duplicate annotation found: $annotationType: $annotation. " +
"Exisitng: ${_map[annotation]}; New: $type.";
}
_map[annotation] = type;
});
});
Expand All @@ -39,6 +34,47 @@ abstract class AnnotationMap<K> {
}
}

abstract class AnnotationsMap<K> {
final Map<K, List<Type>> _map = {};

AnnotationsMap(Injector injector, MetadataExtractor extractMetadata) {
injector.types.forEach((type) {
var meta = extractMetadata(type)
.where((annotation) => annotation is K)
.forEach((annotation) {
_map.putIfAbsent(annotation, () => []).add(type);
});
});
}

List operator[](K annotation) {
var value = _map[annotation];
if (value == null) {
throw 'No $annotation found!';
}
return value;
}

forEach(fn(K, Type)) {
_map.forEach((annotation, types) {
types.forEach((type) {
fn(annotation, type);
});
});
}

List<K> annotationsFor(Type type) {
var res = <K>[];
forEach((ann, annType) {
if (annType == type) {
res.add(ann);
}
});
return res;
}
}


@NgInjectableService()
class MetadataExtractor {

Expand Down
12 changes: 7 additions & 5 deletions lib/core_dom/selector.dart
Original file line number Diff line number Diff line change
Expand Up @@ -274,9 +274,10 @@ DirectiveSelector directiveSelectorFactory(DirectiveMap directives) {
// this directive is matched on any attribute name, and so
// we need to pass the name to the directive by prefixing it to the
// value. Yes it is a bit of a hack.
Type type = directives[selectorRegExp.annotation];
directiveRefs.add(new DirectiveRef(
node, type, selectorRegExp.annotation, '$attrName=$value'));
directives[selectorRegExp.annotation].forEach((type) {
directiveRefs.add(new DirectiveRef(
node, type, selectorRegExp.annotation, '$attrName=$value'));
});
}
}

Expand All @@ -301,8 +302,9 @@ DirectiveSelector directiveSelectorFactory(DirectiveMap directives) {
var selectorRegExp = textSelector[k];

if (selectorRegExp.regexp.hasMatch(value)) {
Type type = directives[selectorRegExp.annotation];
directiveRefs.add(new DirectiveRef(node, type, selectorRegExp.annotation, value));
directives[selectorRegExp.annotation].forEach((type) {
directiveRefs.add(new DirectiveRef(node, type, selectorRegExp.annotation, value));
});
}
}
break;
Expand Down
6 changes: 5 additions & 1 deletion lib/directive/ng_model.dart
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,11 @@ class InputCheckboxDirective {
}

@NgDirective(selector: 'textarea[ng-model]')
@NgDirective(selector: 'input[ng-model]')
@NgDirective(selector: 'input[type=text][ng-model]')
@NgDirective(selector: 'input[type=password][ng-model]')
@NgDirective(selector: 'input[type=url][ng-model]')
@NgDirective(selector: 'input[type=email][ng-model]')
@NgDirective(selector: 'input[type=number][ng-model]')
class InputTextLikeDirective {
dom.Element inputElement;
NgModel ngModel;
Expand Down
4 changes: 2 additions & 2 deletions test/core/registry_spec.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ library registry_spec;
import '../_specs.dart';

main() => describe('RegistryMap', () {
it('should throw error on identical keys', () {
it('should allow for multiple registry keys to be added', () {
var module = new Module()
..type(MyMap)
..type(MetadataExtractor)
Expand All @@ -13,7 +13,7 @@ main() => describe('RegistryMap', () {
var injector = new DynamicInjector(modules: [module]);
expect(() {
injector.get(MyMap);
}).toThrow("Duplicate annotation found: MyAnnotation: A. Exisitng:");
}).not.toThrow();
});

it('should iterate over all types', () {
Expand Down
4 changes: 2 additions & 2 deletions test/core_dom/selector_spec.dart
Original file line number Diff line number Diff line change
Expand Up @@ -169,8 +169,8 @@ main() {
toEqualsDirectiveInfos([
{ "selector": '[ng-model]', "value": 'val', "element": element},
{ "selector": '[probe]', "value": 'i', "element": element},
{ "selector": 'input[ng-model]', "value": 'val', "element": element},
{ "selector": '[ng-model][required]', "value": 'true', "element": element}
{ "selector": '[ng-model][required]', "value": 'true', "element": element},
{ "selector": 'input[type=text][ng-model]', "value": 'val', "element": element}
]));
});

Expand Down
11 changes: 11 additions & 0 deletions test/directive/ng_model_spec.dart
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,17 @@ describe('ng-model', () {
}));


it('should update model from the input value', inject((Scope scope) {
var element = _.compile('<input type="checkbox" ng-model="model">');

element.checked = true;
_.triggerEvent(element, 'change');
expect(scope['model']).toBe(true);

element.checked = false;
_.triggerEvent(element, 'change');
expect(scope['model']).toBe(false);
}));
});

describe('type="textarea"', () {
Expand Down

0 comments on commit dd35653

Please sign in to comment.