Skip to content

Commit ecb0680

Browse files
committed
refactor(proto_view_factory): expose data for generating change detectors
Also consolidates metadata handling in `ElementInjector` BREAKING CHANGE: - renames `DirectiveMetadataReader` into `DirectiveResolver` and removes `src/core/compiler/directive_metadata`. Fixes angular#1712 Fixes angular#1713
1 parent 5114411 commit ecb0680

33 files changed

+683
-434
lines changed

modules/angular2/router.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,15 +18,15 @@ import {Router, RootRouter} from './src/router/router';
1818
import {RouteRegistry} from './src/router/route_registry';
1919
import {Pipeline} from './src/router/pipeline';
2020
import {Location} from './src/router/location';
21-
import {appComponentAnnotatedTypeToken} from './src/core/application_tokens';
21+
import {appComponentRefToken} from './src/core/application_tokens';
2222
import {bind} from './di';
2323

2424
export var routerInjectables:List = [
2525
RouteRegistry,
2626
Pipeline,
2727
BrowserLocation,
2828
Location,
29-
bind(Router).toFactory((registry, pipeline, location, meta) => {
30-
return new RootRouter(registry, pipeline, location, meta.type);
31-
}, [RouteRegistry, Pipeline, Location, appComponentAnnotatedTypeToken])
29+
bind(Router).toFactory((registry, pipeline, location, app) => {
30+
return new RootRouter(registry, pipeline, location, app.hostComponentType);
31+
}, [RouteRegistry, Pipeline, Location, appComponentRefToken])
3232
];

modules/angular2/src/change_detection/interfaces.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,4 +68,4 @@ export class ChangeDetectorDefinition {
6868
constructor(public id: string, public strategy: string, public variableNames: List<string>,
6969
public bindingRecords: List<BindingRecord>,
7070
public directiveRecords: List<DirectiveRecord>) {}
71-
}
71+
}

modules/angular2/src/core/application.js

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import {Parser, Lexer, ChangeDetection, DynamicChangeDetection, PipeRegistry, de
99
import {ExceptionHandler} from './exception_handler';
1010
import {TemplateLoader} from 'angular2/src/render/dom/compiler/template_loader';
1111
import {TemplateResolver} from './compiler/template_resolver';
12-
import {DirectiveMetadataReader} from './compiler/directive_metadata_reader';
12+
import {DirectiveResolver} from './compiler/directive_resolver';
1313
import {List, ListWrapper} from 'angular2/src/facade/collection';
1414
import {Promise, PromiseWrapper} from 'angular2/src/facade/async';
1515
import {NgZone} from 'angular2/src/core/zone/ng_zone';
@@ -39,8 +39,7 @@ import {DefaultDomCompiler} from 'angular2/src/render/dom/compiler/compiler';
3939
import {internalView} from 'angular2/src/core/compiler/view_ref';
4040

4141
import {
42-
appComponentRefToken,
43-
appComponentAnnotatedTypeToken
42+
appComponentRefToken
4443
} from './application_tokens';
4544

4645
var _rootInjector: Injector;
@@ -54,24 +53,22 @@ var _rootBindings = [
5453
function _injectorBindings(appComponentType): List<Binding> {
5554
return [
5655
bind(DOCUMENT_TOKEN).toValue(DOM.defaultDoc()),
57-
bind(appComponentAnnotatedTypeToken).toFactory((reader) => {
58-
// TODO(rado): investigate whether to support bindings on root component.
59-
return reader.read(appComponentType);
60-
}, [DirectiveMetadataReader]),
61-
6256
bind(appComponentRefToken).toAsyncFactory((dynamicComponentLoader, injector,
63-
appComponentAnnotatedType, testability, registry) => {
57+
metadataReader, testability, registry) => {
58+
59+
var annotation = metadataReader.resolve(appComponentType);
6460

65-
var selector = appComponentAnnotatedType.annotation.selector;
66-
return dynamicComponentLoader.loadIntoNewLocation(appComponentAnnotatedType.type, null, selector, injector).then( (componentRef) => {
61+
var selector = annotation.selector;
62+
// TODO(rado): investigate whether to support bindings on root component.
63+
return dynamicComponentLoader.loadIntoNewLocation(appComponentType, null, selector, injector).then( (componentRef) => {
6764
var domView = resolveInternalDomView(componentRef.hostView.render);
6865
// We need to do this here to ensure that we create Testability and
6966
// it's ready on the window for users.
7067
registry.registerApplication(domView.boundElements[0], testability);
7168

7269
return componentRef;
7370
});
74-
}, [DynamicComponentLoader, Injector, appComponentAnnotatedTypeToken,
71+
}, [DynamicComponentLoader, Injector, DirectiveResolver,
7572
Testability, TestabilityRegistry]),
7673

7774
bind(appComponentType).toFactory((ref) => ref.instance,
@@ -109,7 +106,7 @@ function _injectorBindings(appComponentType): List<Binding> {
109106
bind(PipeRegistry).toValue(defaultPipeRegistry),
110107
bind(ChangeDetection).toClass(DynamicChangeDetection),
111108
TemplateLoader,
112-
DirectiveMetadataReader,
109+
DirectiveResolver,
113110
Parser,
114111
Lexer,
115112
ExceptionHandler,
@@ -262,7 +259,7 @@ export function bootstrap(appComponentType: Type,
262259
lc.registerWith(zone, appChangeDetector);
263260
lc.tick(); //the first tick that will bootstrap the app
264261

265-
bootstrapProcess.resolve(new ApplicationRef(componentRef, appInjector));
262+
bootstrapProcess.resolve(new ApplicationRef(componentRef, appComponentType, appInjector));
266263
},
267264

268265
(err) => {
@@ -276,9 +273,15 @@ export function bootstrap(appComponentType: Type,
276273
export class ApplicationRef {
277274
_hostComponent:ComponentRef;
278275
_injector:Injector;
279-
constructor(hostComponent:ComponentRef, injector:Injector) {
276+
_hostComponentType:Type;
277+
constructor(hostComponent:ComponentRef, hostComponentType:Type, injector:Injector) {
280278
this._hostComponent = hostComponent;
281279
this._injector = injector;
280+
this._hostComponentType = hostComponentType;
281+
}
282+
283+
get hostComponentType() {
284+
return this._hostComponentType;
282285
}
283286

284287
get hostComponent() {
Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
11
import {OpaqueToken} from 'angular2/di';
22

33
export var appComponentRefToken:OpaqueToken = new OpaqueToken('ComponentRef');
4-
export var appComponentAnnotatedTypeToken:OpaqueToken = new OpaqueToken('AppComponentAnnotatedType');

modules/angular2/src/core/compiler/compiler.js

Lines changed: 35 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,10 @@ import {Type, isBlank, isPresent, BaseException, normalizeBlank, stringify} from
44
import {Promise, PromiseWrapper} from 'angular2/src/facade/async';
55
import {List, ListWrapper, Map, MapWrapper} from 'angular2/src/facade/collection';
66

7-
import {DirectiveMetadataReader} from './directive_metadata_reader';
8-
import {Component, Directive} from '../annotations_impl/annotations';
7+
import {DirectiveResolver} from './directive_resolver';
8+
99
import {AppProtoView} from './view';
10+
import {ElementBinder} from './element_binder';
1011
import {ProtoViewRef} from './view_ref';
1112
import {DirectiveBinding} from './element_injector';
1213
import {TemplateResolver} from './template_resolver';
@@ -47,7 +48,7 @@ export class CompilerCache {
4748
*/
4849
@Injectable()
4950
export class Compiler {
50-
_reader: DirectiveMetadataReader;
51+
_reader: DirectiveResolver;
5152
_compilerCache:CompilerCache;
5253
_compiling:Map<Type, Promise>;
5354
_templateResolver: TemplateResolver;
@@ -57,7 +58,7 @@ export class Compiler {
5758
_render: renderApi.RenderCompiler;
5859
_protoViewFactory:ProtoViewFactory;
5960

60-
constructor(reader: DirectiveMetadataReader,
61+
constructor(reader: DirectiveResolver,
6162
cache:CompilerCache,
6263
templateResolver: TemplateResolver,
6364
componentUrlMapper: ComponentUrlMapper,
@@ -79,11 +80,11 @@ export class Compiler {
7980
if (directiveTypeOrBinding instanceof DirectiveBinding) {
8081
return directiveTypeOrBinding;
8182
} else if (directiveTypeOrBinding instanceof Binding) {
82-
let meta = this._reader.read(directiveTypeOrBinding.token);
83-
return DirectiveBinding.createFromBinding(directiveTypeOrBinding, meta.annotation);
83+
let annotation = this._reader.resolve(directiveTypeOrBinding.token);
84+
return DirectiveBinding.createFromBinding(directiveTypeOrBinding, annotation);
8485
} else {
85-
let meta = this._reader.read(directiveTypeOrBinding);
86-
return DirectiveBinding.createFromType(meta.type, meta.annotation);
86+
let annotation = this._reader.resolve(directiveTypeOrBinding);
87+
return DirectiveBinding.createFromType(directiveTypeOrBinding, annotation);
8788
}
8889
}
8990

@@ -93,9 +94,9 @@ export class Compiler {
9394
var componentBinding = this._bindDirective(componentTypeOrBinding);
9495
this._assertTypeIsComponent(componentBinding);
9596

96-
var directiveMetadata = Compiler.buildRenderDirective(componentBinding);
97+
var directiveMetadata = componentBinding.metadata;
9798
return this._render.compileHost(directiveMetadata).then( (hostRenderPv) => {
98-
return this._compileNestedProtoViews(null, null, hostRenderPv, [componentBinding], true);
99+
return this._compileNestedProtoViews(componentBinding, hostRenderPv, [componentBinding]);
99100
}).then( (appProtoView) => {
100101
return new ProtoViewRef(appProtoView);
101102
});
@@ -139,44 +140,39 @@ export class Compiler {
139140
);
140141
var renderTemplate = this._buildRenderTemplate(component, template, directives);
141142
pvPromise = this._render.compile(renderTemplate).then( (renderPv) => {
142-
return this._compileNestedProtoViews(null, componentBinding, renderPv, directives, true);
143+
return this._compileNestedProtoViews(componentBinding, renderPv, directives);
143144
});
144145

145146
MapWrapper.set(this._compiling, component, pvPromise);
146147
return pvPromise;
147148
}
148149

149150
// TODO(tbosch): union type return AppProtoView or Promise<AppProtoView>
150-
_compileNestedProtoViews(parentProtoView, componentBinding, renderPv, directives, isComponentRootView) {
151-
var nestedPVPromises = [];
152-
var protoView = this._protoViewFactory.createProtoView(parentProtoView, componentBinding, renderPv, directives);
153-
if (isComponentRootView && isPresent(componentBinding)) {
151+
_compileNestedProtoViews(componentBinding, renderPv, directives) {
152+
var protoViews = this._protoViewFactory.createAppProtoViews(componentBinding, renderPv, directives);
153+
var protoView = protoViews[0];
154+
// TODO(tbosch): we should be caching host protoViews as well!
155+
// -> need a separate cache for this...
156+
if (renderPv.type === renderApi.ProtoViewDto.COMPONENT_VIEW_TYPE && isPresent(componentBinding)) {
154157
// Populate the cache before compiling the nested components,
155158
// so that components can reference themselves in their template.
156159
var component = componentBinding.key.token;
157160
this._compilerCache.set(component, protoView);
158161
MapWrapper.delete(this._compiling, component);
159162
}
160163

161-
var binderIndex = 0;
162-
ListWrapper.forEach(protoView.elementBinders, (elementBinder) => {
164+
var nestedPVPromises = [];
165+
ListWrapper.forEach(this._collectComponentElementBinders(protoViews), (elementBinder) => {
163166
var nestedComponent = elementBinder.componentDirective;
164-
var nestedRenderProtoView = renderPv.elementBinders[binderIndex].nestedProtoView;
165167
var elementBinderDone = (nestedPv) => {
166168
elementBinder.nestedProtoView = nestedPv;
167169
};
168-
var nestedCall = null;
169-
if (isPresent(nestedComponent)) {
170-
nestedCall = this._compile(nestedComponent);
171-
} else if (isPresent(nestedRenderProtoView)) {
172-
nestedCall = this._compileNestedProtoViews(protoView, componentBinding, nestedRenderProtoView, directives, false);
173-
}
170+
var nestedCall = this._compile(nestedComponent);
174171
if (PromiseWrapper.isPromise(nestedCall)) {
175172
ListWrapper.push(nestedPVPromises, nestedCall.then(elementBinderDone));
176173
} else if (isPresent(nestedCall)) {
177174
elementBinderDone(nestedCall);
178175
}
179-
binderIndex++;
180176
});
181177

182178
var protoViewDone = (_) => {
@@ -189,6 +185,18 @@ export class Compiler {
189185
}
190186
}
191187

188+
_collectComponentElementBinders(protoViews:List<AppProtoView>):List<ElementBinder> {
189+
var componentElementBinders = [];
190+
ListWrapper.forEach(protoViews, (protoView) => {
191+
ListWrapper.forEach(protoView.elementBinders, (elementBinder) => {
192+
if (isPresent(elementBinder.componentDirective)) {
193+
ListWrapper.push(componentElementBinders, elementBinder);
194+
}
195+
});
196+
});
197+
return componentElementBinders;
198+
}
199+
192200
_buildRenderTemplate(component, view, directives): renderApi.ViewDefinition {
193201
var componentUrl = this._urlResolver.resolve(
194202
this._appUrl, this._componentUrlMapper.getUrl(component)
@@ -206,36 +214,7 @@ export class Compiler {
206214
componentId: stringify(component),
207215
absUrl: templateAbsUrl,
208216
template: view.template,
209-
directives: ListWrapper.map(directives, Compiler.buildRenderDirective)
210-
});
211-
}
212-
213-
static buildRenderDirective(directiveBinding):renderApi.DirectiveMetadata {
214-
var ann = directiveBinding.annotation;
215-
var renderType;
216-
var compileChildren = ann.compileChildren;
217-
if (ann instanceof Component) {
218-
renderType = renderApi.DirectiveMetadata.COMPONENT_TYPE;
219-
} else {
220-
renderType = renderApi.DirectiveMetadata.DIRECTIVE_TYPE;
221-
}
222-
var readAttributes = [];
223-
ListWrapper.forEach(directiveBinding.dependencies, (dep) => {
224-
if (isPresent(dep.attributeName)) {
225-
ListWrapper.push(readAttributes, dep.attributeName);
226-
}
227-
});
228-
return new renderApi.DirectiveMetadata({
229-
id: stringify(directiveBinding.key.token),
230-
type: renderType,
231-
selector: ann.selector,
232-
compileChildren: compileChildren,
233-
hostListeners: isPresent(ann.hostListeners) ? MapWrapper.createFromStringMap(ann.hostListeners) : null,
234-
hostProperties: isPresent(ann.hostProperties) ? MapWrapper.createFromStringMap(ann.hostProperties) : null,
235-
hostAttributes: isPresent(ann.hostAttributes) ? MapWrapper.createFromStringMap(ann.hostAttributes) : null,
236-
hostActions: isPresent(ann.hostActions) ? MapWrapper.createFromStringMap(ann.hostActions) : null,
237-
properties: isPresent(ann.properties) ? MapWrapper.createFromStringMap(ann.properties) : null,
238-
readAttributes: readAttributes
217+
directives: ListWrapper.map(directives, directiveBinding => directiveBinding.metadata )
239218
});
240219
}
241220

@@ -260,7 +239,7 @@ export class Compiler {
260239
}
261240

262241
_assertTypeIsComponent(directiveBinding:DirectiveBinding):void {
263-
if (!(directiveBinding.annotation instanceof Component)) {
242+
if (directiveBinding.metadata.type !== renderApi.DirectiveMetadata.COMPONENT_TYPE) {
264243
throw new BaseException(`Could not load '${stringify(directiveBinding.key.token)}' because it is not a component.`);
265244
}
266245
}

modules/angular2/src/core/compiler/directive_metadata.js

Lines changed: 0 additions & 19 deletions
This file was deleted.

modules/angular2/src/core/compiler/directive_metadata_reader.js renamed to modules/angular2/src/core/compiler/directive_resolver.js

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,18 @@
1-
import {Injector} from 'angular2/di';
21
import {Injectable} from 'angular2/src/di/annotations_impl';
32
import {Type, isPresent, BaseException, stringify} from 'angular2/src/facade/lang';
4-
import {Directive, Component} from '../annotations_impl/annotations';
5-
import {DirectiveMetadata} from './directive_metadata';
3+
import {Directive} from '../annotations_impl/annotations';
64
import {reflector} from 'angular2/src/reflection/reflection';
75

86
@Injectable()
9-
export class DirectiveMetadataReader {
10-
read(type:Type):DirectiveMetadata {
7+
export class DirectiveResolver {
8+
resolve(type:Type):Directive {
119
var annotations = reflector.annotations(type);
1210
if (isPresent(annotations)) {
1311
for (var i=0; i<annotations.length; i++) {
1412
var annotation = annotations[i];
1513

1614
if (annotation instanceof Directive) {
17-
var resolvedInjectables = null;
18-
if (annotation instanceof Component && isPresent(annotation.injectables)) {
19-
resolvedInjectables = Injector.resolve(annotation.injectables);
20-
}
21-
return new DirectiveMetadata(type, annotation, resolvedInjectables);
15+
return annotation;
2216
}
2317
}
2418
}

0 commit comments

Comments
 (0)