Skip to content

Commit 09f8d8f

Browse files
committed
refactor(core): introduce ViewRef and ProtoViewRef
BREAKING CHANGES: - `NgElement` merged into `ElementRef` - `Compiler.compile…` returns `ProtoViewRef` - `ViewContainer` uses `ProtoViewRef`s and `ViewRef`s. - `ViewRef`/`ProtoViewRef` in renderer were renamed to `RenderViewRef`/`RenderProtoViewRef`. Related to angular#1477 Closes angular#1592
1 parent 1205f54 commit 09f8d8f

35 files changed

+473
-404
lines changed

modules/angular2/core.js

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,7 @@ export * from './src/render/dom/shadow_dom/native_shadow_dom_strategy';
2121
export * from './src/render/dom/shadow_dom/emulated_scoped_shadow_dom_strategy';
2222
export * from './src/render/dom/shadow_dom/emulated_unscoped_shadow_dom_strategy';
2323
export * from './src/core/compiler/dynamic_component_loader';
24-
export {ElementRef, ComponentRef} from './src/core/compiler/element_injector';
25-
export * from './src/core/compiler/view';
26-
export * from './src/core/compiler/view_container_ref';
27-
28-
export * from './src/core/compiler/ng_element';
24+
export {ViewRef, ProtoViewRef} from './src/core/compiler/view_ref';
25+
export {ViewContainerRef} from './src/core/compiler/view_container_ref';
26+
export {ElementRef} from './src/core/compiler/element_ref';
2927

modules/angular2/src/core/annotations/annotations.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ import {DEFAULT} from 'angular2/change_detection';
5454
* - `@Descendants query:Query<DirectiveType>`: A live collection of any child directives (will be implemented in later relaese).
5555
*
5656
* To inject element-specific special objects, declare the constructor parameter as:
57-
* - `element: NgElement` to obtain a DOM element (DEPRECATED: replacement coming)
57+
* - `element: ElementRef` to obtain a reference to logical element in the view.
5858
* - `viewContainer: ViewContainerRef` to control child template instantiation, for {@link Viewport} directives only
5959
* - `bindingPropagation: BindingPropagation` to control change detection in a more granular way.
6060
*

modules/angular2/src/core/application.js

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,10 @@ import {DirectDomRenderer} from 'angular2/src/render/dom/direct_dom_renderer';
3737
import * as rc from 'angular2/src/render/dom/compiler/compiler';
3838
import * as rvf from 'angular2/src/render/dom/view/view_factory';
3939
import * as rvh from 'angular2/src/render/dom/view/view_hydrator';
40+
import {internalView} from 'angular2/src/core/compiler/view_ref';
4041

4142
import {
4243
appComponentRefToken,
43-
appChangeDetectorToken,
4444
appElementToken,
4545
appComponentAnnotatedTypeToken,
4646
appDocumentToken,
@@ -80,8 +80,6 @@ function _injectorBindings(appComponentType): List<Binding> {
8080
}, [DynamicComponentLoader, Injector, appElementToken, appComponentAnnotatedTypeToken,
8181
Testability, TestabilityRegistry]),
8282

83-
bind(appChangeDetectorToken).toFactory((ref) => ref.hostView.changeDetector,
84-
[appComponentRefToken]),
8583
bind(appComponentType).toFactory((ref) => ref.instance,
8684
[appComponentRefToken]),
8785
bind(LifeCycle).toFactory((exceptionHandler) => new LifeCycle(exceptionHandler, null, assertionsEnabled()),[ExceptionHandler]),
@@ -253,7 +251,7 @@ function _createVmZone(givenReporter:Function): VmTurnZone {
253251
*/
254252
export function bootstrap(appComponentType: Type,
255253
componentInjectableBindings: List<Binding> = null,
256-
errorReporter: Function = null): Promise<ComponentRef> {
254+
errorReporter: Function = null): Promise<ApplicationRef> {
257255
BrowserDomAdapter.makeCurrent();
258256
var bootstrapProcess = PromiseWrapper.completer();
259257

@@ -266,13 +264,13 @@ export function bootstrap(appComponentType: Type,
266264

267265
PromiseWrapper.then(appInjector.asyncGet(appComponentRefToken),
268266
(componentRef) => {
269-
var appChangeDetector = componentRef.hostView.changeDetector;
267+
var appChangeDetector = internalView(componentRef.hostView).changeDetector;
270268
// retrieve life cycle: may have already been created if injected in root component
271269
var lc = appInjector.get(LifeCycle);
272270
lc.registerWith(zone, appChangeDetector);
273271
lc.tick(); //the first tick that will bootstrap the app
274272

275-
bootstrapProcess.resolve(componentRef);
273+
bootstrapProcess.resolve(new ApplicationRef(componentRef, appInjector));
276274
},
277275

278276
(err) => {
@@ -283,6 +281,28 @@ export function bootstrap(appComponentType: Type,
283281
return bootstrapProcess.promise;
284282
}
285283

284+
export class ApplicationRef {
285+
_hostComponent:ComponentRef;
286+
_injector:Injector;
287+
constructor(hostComponent:ComponentRef, injector:Injector) {
288+
this._hostComponent = hostComponent;
289+
this._injector = injector;
290+
}
291+
292+
get hostComponent() {
293+
return this._hostComponent.instance;
294+
}
295+
296+
dispose() {
297+
// TODO: We also need to clean up the Zone, ... here!
298+
return this._hostComponent.dispose();
299+
}
300+
301+
get injector() {
302+
return this._injector;
303+
}
304+
}
305+
286306
function _createAppInjector(appComponentType: Type, bindings: List<Binding>, zone: VmTurnZone): Injector {
287307
if (isBlank(_rootInjector)) _rootInjector = Injector.resolveAndCreate(_rootBindings);
288308
var mergedBindings = isPresent(bindings) ?
Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import {OpaqueToken} from 'angular2/di';
22

33
export var appComponentRefToken:OpaqueToken = new OpaqueToken('ComponentRef');
4-
export var appChangeDetectorToken:OpaqueToken = new OpaqueToken('AppChangeDetector');
54
export var appElementToken:OpaqueToken = new OpaqueToken('AppElement');
65
export var appComponentAnnotatedTypeToken:OpaqueToken = new OpaqueToken('AppComponentAnnotatedType');
76
export var appDocumentToken:OpaqueToken = new OpaqueToken('AppDocument');

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

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {List, ListWrapper, Map, MapWrapper} from 'angular2/src/facade/collection
66
import {DirectiveMetadataReader} from './directive_metadata_reader';
77
import {Component, Viewport, DynamicComponent, Decorator} from '../annotations/annotations';
88
import {AppProtoView} from './view';
9+
import {ProtoViewRef} from './view_ref';
910
import {DirectiveBinding} from './element_injector';
1011
import {TemplateResolver} from './template_resolver';
1112
import {View} from '../annotations/view';
@@ -87,21 +88,26 @@ export class Compiler {
8788

8889
// Create a hostView as if the compiler encountered <hostcmp></hostcmp>.
8990
// Used for bootstrapping.
90-
compileInHost(componentTypeOrBinding:any):Promise<AppProtoView> {
91+
compileInHost(componentTypeOrBinding:any):Promise<ProtoViewRef> {
9192
var componentBinding = this._bindDirective(componentTypeOrBinding);
9293
this._assertTypeIsComponent(componentBinding);
93-
94+
9495
var directiveMetadata = Compiler.buildRenderDirective(componentBinding);
9596
return this._renderer.createHostProtoView(directiveMetadata).then( (hostRenderPv) => {
9697
return this._compileNestedProtoViews(null, hostRenderPv, [componentBinding], true);
98+
}).then( (appProtoView) => {
99+
return new ProtoViewRef(appProtoView);
97100
});
98101
}
99102

100-
compile(component: Type):Promise<AppProtoView> {
103+
compile(component: Type):Promise<ProtoViewRef> {
101104
var componentBinding = this._bindDirective(component);
102105
this._assertTypeIsComponent(componentBinding);
103106
var protoView = this._compile(componentBinding);
104-
return PromiseWrapper.isPromise(protoView) ? protoView : PromiseWrapper.resolve(protoView);
107+
var pvPromise = PromiseWrapper.isPromise(protoView) ? protoView : PromiseWrapper.resolve(protoView);
108+
return pvPromise.then( (appProtoView) => {
109+
return new ProtoViewRef(appProtoView);
110+
});
105111
}
106112

107113
// TODO(vicb): union type return AppProtoView or Promise<AppProtoView>

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

Lines changed: 24 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -2,32 +2,25 @@ import {Key, Injector, Injectable, ResolvedBinding, Binding, bind} from 'angular
22
import {Compiler} from './compiler';
33
import {Type, BaseException, stringify, isPresent} from 'angular2/src/facade/lang';
44
import {Promise} from 'angular2/src/facade/async';
5-
import {AppViewManager} from 'angular2/src/core/compiler/view_manager';
6-
import {ElementRef} from './element_injector';
7-
import {AppView} from './view';
5+
import {AppViewManager, ComponentCreateResult} from 'angular2/src/core/compiler/view_manager';
6+
import {ElementRef} from './element_ref';
87

98
/**
109
* @exportedAs angular2/view
1110
*/
1211
export class ComponentRef {
1312
location:ElementRef;
1413
instance:any;
15-
componentView:AppView;
1614
_dispose:Function;
1715

18-
constructor(location:ElementRef, instance:any, componentView:AppView, dispose:Function){
16+
constructor(location:ElementRef, instance:any, dispose:Function) {
1917
this.location = location;
2018
this.instance = instance;
21-
this.componentView = componentView;
2219
this._dispose = dispose;
2320
}
2421

25-
get injector() {
26-
return this.location.injector;
27-
}
28-
2922
get hostView() {
30-
return this.location.hostView;
23+
return this.location.parentView;
3124
}
3225

3326
dispose() {
@@ -58,12 +51,12 @@ export class DynamicComponentLoader {
5851
*/
5952
loadIntoExistingLocation(typeOrBinding, location:ElementRef, injector:Injector = null):Promise<ComponentRef> {
6053
var binding = this._getBinding(typeOrBinding);
61-
return this._compiler.compile(binding.token).then(componentProtoView => {
62-
var componentView = this._viewManager.createDynamicComponentView(
63-
location, componentProtoView, binding, injector);
64-
54+
return this._compiler.compile(binding.token).then(componentProtoViewRef => {
55+
this._viewManager.createDynamicComponentView(
56+
location, componentProtoViewRef, binding, injector);
57+
var component = this._viewManager.getComponent(location);
6558
var dispose = () => {throw new BaseException("Not implemented");};
66-
return new ComponentRef(location, location.elementInjector.getDynamicallyLoadedComponent(), componentView, dispose);
59+
return new ComponentRef(location, component, dispose);
6760
});
6861
}
6962

@@ -73,16 +66,16 @@ export class DynamicComponentLoader {
7366
*/
7467
loadIntoNewLocation(typeOrBinding, parentComponentLocation:ElementRef, elementOrSelector:any,
7568
injector:Injector = null):Promise<ComponentRef> {
76-
return this._compiler.compileInHost(this._getBinding(typeOrBinding)).then(hostProtoView => {
77-
var hostView = this._viewManager.createInPlaceHostView(
78-
parentComponentLocation, elementOrSelector, hostProtoView, injector);
69+
return this._compiler.compileInHost(this._getBinding(typeOrBinding)).then(hostProtoViewRef => {
70+
var hostViewRef = this._viewManager.createInPlaceHostView(
71+
parentComponentLocation, elementOrSelector, hostProtoViewRef, injector);
72+
var newLocation = new ElementRef(hostViewRef, 0);
73+
var component = this._viewManager.getComponent(newLocation);
7974

80-
var newLocation = hostView.elementInjectors[0].getElementRef();
81-
var component = hostView.elementInjectors[0].getComponent();
8275
var dispose = () => {
83-
this._viewManager.destroyInPlaceHostView(parentComponentLocation, hostView);
76+
this._viewManager.destroyInPlaceHostView(parentComponentLocation, hostViewRef);
8477
};
85-
return new ComponentRef(newLocation, component, hostView.componentChildViews[0], dispose);
78+
return new ComponentRef(newLocation, component, dispose);
8679
});
8780
}
8881

@@ -92,16 +85,17 @@ export class DynamicComponentLoader {
9285
*/
9386
loadNextToExistingLocation(typeOrBinding, location:ElementRef, injector:Injector = null):Promise<ComponentRef> {
9487
var binding = this._getBinding(typeOrBinding);
95-
return this._compiler.compileInHost(binding).then(hostProtoView => {
96-
var hostView = location.viewContainer.create(-1, hostProtoView, injector);
88+
return this._compiler.compileInHost(binding).then(hostProtoViewRef => {
89+
var viewContainer = this._viewManager.getViewContainer(location);
90+
var hostViewRef = viewContainer.create(-1, hostProtoViewRef, injector);
91+
var newLocation = new ElementRef(hostViewRef, 0);
92+
var component = this._viewManager.getComponent(newLocation);
9793

98-
var newLocation = hostView.elementInjectors[0].getElementRef();
99-
var component = hostView.elementInjectors[0].getComponent();
10094
var dispose = () => {
101-
var index = location.viewContainer.indexOf(hostView);
102-
location.viewContainer.remove(index);
95+
var index = viewContainer.indexOf(hostViewRef);
96+
viewContainer.remove(index);
10397
};
104-
return new ComponentRef(newLocation, component, hostView.componentChildViews[0], dispose);
98+
return new ComponentRef(newLocation, component, dispose);
10599
});
106100
}
107101

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

Lines changed: 18 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,11 @@ import {Injector, Key, Dependency, bind, Binding, ResolvedBinding, NoBindingErro
66
AbstractBindingError, CyclicDependencyError} from 'angular2/di';
77
import {Parent, Ancestor} from 'angular2/src/core/annotations/visibility';
88
import {Attribute, Query} from 'angular2/src/core/annotations/di';
9-
import * as viewModule from 'angular2/src/core/compiler/view';
9+
import * as viewModule from './view';
1010
import * as avmModule from './view_manager';
11-
import {ViewContainerRef} from 'angular2/src/core/compiler/view_container_ref';
12-
import {NgElement} from 'angular2/src/core/compiler/ng_element';
11+
import {ViewContainerRef} from './view_container_ref';
12+
import {ElementRef} from './element_ref';
13+
import {ProtoViewRef, ViewRef} from './view_ref';
1314
import {Directive, Component, onChange, onDestroy, onAllChangesDone} from 'angular2/src/core/annotations/annotations';
1415
import {ChangeDetector, ChangeDetectorRef} from 'angular2/change_detection';
1516
import {QueryList} from './query_list';
@@ -23,40 +24,17 @@ var _undefined = new Object();
2324

2425
var _staticKeys;
2526

26-
/**
27-
* @exportedAs angular2/view
28-
*/
29-
export class ElementRef {
30-
hostView:viewModule.AppView;
31-
boundElementIndex:number;
32-
injector:Injector;
33-
elementInjector:ElementInjector;
34-
viewContainer:ViewContainerRef;
35-
36-
constructor(elementInjector, hostView, boundElementIndex, injector, viewManager, defaultProtoView){
37-
this.elementInjector = elementInjector;
38-
this.hostView = hostView;
39-
this.boundElementIndex = boundElementIndex;
40-
this.injector = injector;
41-
this.viewContainer = new ViewContainerRef(viewManager, this, defaultProtoView);
42-
}
43-
}
44-
4527
class StaticKeys {
4628
viewManagerId:number;
47-
viewId:number;
48-
ngElementId:number;
49-
defaultProtoViewId:number;
29+
protoViewId:number;
5030
viewContainerId:number;
5131
changeDetectorRefId:number;
5232
elementRefId:number;
5333

5434
constructor() {
5535
//TODO: vsavkin Key.annotate(Key.get(AppView), 'static')
5636
this.viewManagerId = Key.get(avmModule.AppViewManager).id;
57-
this.defaultProtoViewId = Key.get(viewModule.AppProtoView).id;
58-
this.viewId = Key.get(viewModule.AppView).id;
59-
this.ngElementId = Key.get(NgElement).id;
37+
this.protoViewId = Key.get(ProtoViewRef).id;
6038
this.viewContainerId = Key.get(ViewContainerRef).id;
6139
this.changeDetectorRefId = Key.get(ChangeDetectorRef).id;
6240
this.elementRefId = Key.get(ElementRef).id;
@@ -294,14 +272,12 @@ export class DirectiveBinding extends ResolvedBinding {
294272
// TODO(rado): benchmark and consider rolling in as ElementInjector fields.
295273
export class PreBuiltObjects {
296274
viewManager:avmModule.AppViewManager;
297-
defaultProtoView:viewModule.AppProtoView;
275+
protoView:viewModule.AppProtoView;
298276
view:viewModule.AppView;
299-
element:NgElement;
300-
constructor(viewManager:avmModule.AppViewManager, view:viewModule.AppView, element:NgElement, defaultProtoView:viewModule.AppProtoView) {
277+
constructor(viewManager:avmModule.AppViewManager, view:viewModule.AppView, protoView:viewModule.AppProtoView) {
301278
this.viewManager = viewManager;
302279
this.view = view;
303-
this.defaultProtoView = defaultProtoView;
304-
this.element = element;
280+
this.protoView = protoView;
305281
}
306282
}
307283

@@ -649,11 +625,6 @@ export class ElementInjector extends TreeNode {
649625
return this._proto.eventEmitterAccessors;
650626
}
651627

652-
/** Gets the NgElement associated with this ElementInjector */
653-
getNgElement() {
654-
return this._preBuiltObjects.element;
655-
}
656-
657628
getComponent() {
658629
if (this._proto._binding0IsComponent) {
659630
return this._obj0;
@@ -663,8 +634,11 @@ export class ElementInjector extends TreeNode {
663634
}
664635

665636
getElementRef() {
666-
return new ElementRef(this, this._preBuiltObjects.view, this._proto.index, this._lightDomAppInjector,
667-
this._preBuiltObjects.viewManager, this._preBuiltObjects.defaultProtoView);
637+
return new ElementRef(new ViewRef(this._preBuiltObjects.view), this._proto.index);
638+
}
639+
640+
getViewContainerRef() {
641+
return new ViewContainerRef(this._preBuiltObjects.viewManager, this.getElementRef(), new ProtoViewRef(this._preBuiltObjects.protoView));
668642
}
669643

670644
getDynamicallyLoadedComponent() {
@@ -742,7 +716,10 @@ export class ElementInjector extends TreeNode {
742716
return this.getElementRef();
743717
}
744718
if (dep.key.id === StaticKeys.instance().viewContainerId) {
745-
return this.getElementRef().viewContainer;
719+
return this.getViewContainerRef();
720+
}
721+
if (dep.key.id === StaticKeys.instance().protoViewId) {
722+
return new ProtoViewRef(this._preBuiltObjects.protoView);
746723
}
747724
return this._getByKey(dep.key, dep.depth, dep.optional, requestor);
748725
}
@@ -914,11 +891,7 @@ export class ElementInjector extends TreeNode {
914891

915892
_getPreBuiltObjectByKeyId(keyId:int) {
916893
var staticKeys = StaticKeys.instance();
917-
// TODO: AppView should not be injectable. Remove it.
918894
if (keyId === staticKeys.viewManagerId) return this._preBuiltObjects.viewManagerId;
919-
if (keyId === staticKeys.viewId) return this._preBuiltObjects.view;
920-
if (keyId === staticKeys.ngElementId) return this._preBuiltObjects.element;
921-
if (keyId === staticKeys.defaultProtoViewId) return this._preBuiltObjects.defaultProtoView;
922895

923896
//TODO add other objects as needed
924897
return _undefined;

0 commit comments

Comments
 (0)