feat(element_injector): added PrivateComponentLocation
This commit is contained in:
parent
b69f3043e0
commit
7488456d68
|
@ -7,8 +7,9 @@ import {EventEmitter, PropertySetter} from 'angular2/src/core/annotations/di';
|
|||
import * as viewModule from 'angular2/src/core/compiler/view';
|
||||
import {ViewContainer} from 'angular2/src/core/compiler/view_container';
|
||||
import {NgElement} from 'angular2/src/core/dom/element';
|
||||
import {Directive, onChange, onDestroy} from 'angular2/src/core/annotations/annotations'
|
||||
import {BindingPropagationConfig} from 'angular2/src/core/compiler/binding_propagation_config'
|
||||
import {Directive, onChange, onDestroy} from 'angular2/src/core/annotations/annotations';
|
||||
import {BindingPropagationConfig} from 'angular2/src/core/compiler/binding_propagation_config';
|
||||
import {PrivateComponentLocation} from 'angular2/src/core/compiler/private_component_location';
|
||||
import {reflector} from 'angular2/src/reflection/reflection';
|
||||
|
||||
var _MAX_DIRECTIVE_CONSTRUCTION_COUNTER = 10;
|
||||
|
@ -24,6 +25,7 @@ class StaticKeys {
|
|||
ngElementId:number;
|
||||
viewContainerId:number;
|
||||
bindingPropagationConfigId:number;
|
||||
privateComponentLocationId:number;
|
||||
|
||||
constructor() {
|
||||
//TODO: vsavkin Key.annotate(Key.get(View), 'static')
|
||||
|
@ -31,6 +33,7 @@ class StaticKeys {
|
|||
this.ngElementId = Key.get(NgElement).id;
|
||||
this.viewContainerId = Key.get(ViewContainer).id;
|
||||
this.bindingPropagationConfigId = Key.get(BindingPropagationConfig).id;
|
||||
this.privateComponentLocationId = Key.get(PrivateComponentLocation).id;
|
||||
}
|
||||
|
||||
static instance() {
|
||||
|
@ -155,7 +158,6 @@ export class DirectiveBinding extends Binding {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
// TODO(rado): benchmark and consider rolling in as ElementInjector fields.
|
||||
export class PreBuiltObjects {
|
||||
view:viewModule.View;
|
||||
|
@ -317,6 +319,8 @@ export class ElementInjector extends TreeNode {
|
|||
_obj9:any;
|
||||
_preBuiltObjects;
|
||||
_constructionCounter;
|
||||
_privateComponent;
|
||||
_privateComponentBinding:DirectiveBinding;
|
||||
|
||||
constructor(proto:ProtoElementInjector, parent:ElementInjector, host:ElementInjector) {
|
||||
super(parent);
|
||||
|
@ -366,6 +370,9 @@ export class ElementInjector extends TreeNode {
|
|||
if (isPresent(p._binding7) && p._binding7.callOnDestroy) {this._obj7.onDestroy();}
|
||||
if (isPresent(p._binding8) && p._binding8.callOnDestroy) {this._obj8.onDestroy();}
|
||||
if (isPresent(p._binding9) && p._binding9.callOnDestroy) {this._obj9.onDestroy();}
|
||||
if (isPresent(this._privateComponentBinding) && this._privateComponentBinding.callOnDestroy) {
|
||||
this._privateComponent.onDestroy();
|
||||
}
|
||||
|
||||
this._obj0 = null;
|
||||
this._obj1 = null;
|
||||
|
@ -377,6 +384,7 @@ export class ElementInjector extends TreeNode {
|
|||
this._obj7 = null;
|
||||
this._obj8 = null;
|
||||
this._obj9 = null;
|
||||
this._privateComponent = null;
|
||||
|
||||
this._constructionCounter = 0;
|
||||
}
|
||||
|
@ -399,6 +407,15 @@ export class ElementInjector extends TreeNode {
|
|||
if (isPresent(p._keyId7)) this._getDirectiveByKeyId(p._keyId7);
|
||||
if (isPresent(p._keyId8)) this._getDirectiveByKeyId(p._keyId8);
|
||||
if (isPresent(p._keyId9)) this._getDirectiveByKeyId(p._keyId9);
|
||||
if (isPresent(this._privateComponentBinding)) {
|
||||
this._privateComponent = this._new(this._privateComponentBinding);
|
||||
}
|
||||
}
|
||||
|
||||
createPrivateComponent(componentType:Type, annotation:Directive) {
|
||||
this._privateComponentBinding = DirectiveBinding.createFromType(componentType, annotation);
|
||||
this._privateComponent = this._new(this._privateComponentBinding);
|
||||
return this._privateComponent;
|
||||
}
|
||||
|
||||
_checkShadowDomAppInjector(shadowDomAppInjector:Injector) {
|
||||
|
@ -439,6 +456,14 @@ export class ElementInjector extends TreeNode {
|
|||
}
|
||||
}
|
||||
|
||||
getPrivateComponent() {
|
||||
return this._privateComponent;
|
||||
}
|
||||
|
||||
getShadowDomAppInjector() {
|
||||
return this._shadowDomAppInjector;
|
||||
}
|
||||
|
||||
directParent(): ElementInjector {
|
||||
return this._proto.distanceToParent < 2 ? this.parent : null;
|
||||
}
|
||||
|
@ -447,6 +472,10 @@ export class ElementInjector extends TreeNode {
|
|||
return this._proto._binding0IsComponent && key.id === this._proto._keyId0;
|
||||
}
|
||||
|
||||
_isPrivateComponentKey(key:Key) {
|
||||
return isPresent(this._privateComponentBinding) && key.id === this._privateComponentBinding.key.id;
|
||||
}
|
||||
|
||||
_new(binding:Binding) {
|
||||
if (this._constructionCounter++ > _MAX_DIRECTIVE_CONSTRUCTION_COUNTER) {
|
||||
throw new CyclicDependencyError(binding.key);
|
||||
|
@ -545,6 +574,8 @@ export class ElementInjector extends TreeNode {
|
|||
|
||||
if (isPresent(this._host) && this._host._isComponentKey(key)) {
|
||||
return this._host.getComponent();
|
||||
} else if (isPresent(this._host) && this._host._isPrivateComponentKey(key)) {
|
||||
return this._host.getPrivateComponent();
|
||||
} else if (optional) {
|
||||
return this._appInjector(requestor).getOptional(key);
|
||||
} else {
|
||||
|
@ -571,6 +602,10 @@ export class ElementInjector extends TreeNode {
|
|||
if (keyId === staticKeys.viewContainerId) return this._preBuiltObjects.viewContainer;
|
||||
if (keyId === staticKeys.bindingPropagationConfigId) return this._preBuiltObjects.bindingPropagationConfig;
|
||||
|
||||
if (keyId === staticKeys.privateComponentLocationId) {
|
||||
return new PrivateComponentLocation(this, this._preBuiltObjects.element, this._preBuiltObjects.view);
|
||||
}
|
||||
|
||||
//TODO add other objects as needed
|
||||
return _undefined;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
import {Directive} from 'angular2/src/core/annotations/annotations'
|
||||
import {NgElement} from 'angular2/src/core/dom/element';
|
||||
import {ElementInjector} from './element_injector';
|
||||
import {ProtoView, View} from './view';
|
||||
import {ShadowDomStrategy} from './shadow_dom_strategy';
|
||||
import {EventManager} from 'angular2/src/core/events/event_manager';
|
||||
import {ListWrapper} from 'angular2/src/facade/collection';
|
||||
import {Type} from 'angular2/src/facade/lang';
|
||||
|
||||
|
||||
export class PrivateComponentLocation {
|
||||
_elementInjector:ElementInjector;
|
||||
_elt:NgElement;
|
||||
_view:View;
|
||||
|
||||
constructor(elementInjector:ElementInjector, elt:NgElement, view:View){
|
||||
this._elementInjector = elementInjector;
|
||||
this._elt = elt;
|
||||
this._view = view;
|
||||
}
|
||||
|
||||
createComponent(type:Type, annotation:Directive, componentProtoView:ProtoView,
|
||||
eventManager:EventManager, shadowDomStrategy:ShadowDomStrategy) {
|
||||
var context = this._elementInjector.createPrivateComponent(type, annotation);
|
||||
|
||||
var view = componentProtoView.instantiate(this._elementInjector, eventManager);
|
||||
view.hydrate(this._elementInjector.getShadowDomAppInjector(), this._elementInjector, context);
|
||||
|
||||
shadowDomStrategy.attachTemplate(this._elt.domElement, view);
|
||||
|
||||
ListWrapper.push(this._view.componentChildViews, view);
|
||||
this._view.changeDetector.addChild(view.changeDetector);
|
||||
}
|
||||
}
|
|
@ -114,6 +114,7 @@ class DirectiveWithDestroy {
|
|||
|
||||
export function main() {
|
||||
var defaultPreBuiltObjects = new PreBuiltObjects(null, null, null, null);
|
||||
var appInjector = new Injector([]);
|
||||
|
||||
function humanize(tree, names:List) {
|
||||
var lookupName = (item) =>
|
||||
|
@ -126,7 +127,7 @@ export function main() {
|
|||
}
|
||||
|
||||
function injector(bindings, lightDomAppInjector = null, shadowDomAppInjector = null, preBuiltObjects = null) {
|
||||
if (isBlank(lightDomAppInjector)) lightDomAppInjector = new Injector([]);
|
||||
if (isBlank(lightDomAppInjector)) lightDomAppInjector = appInjector;
|
||||
|
||||
var proto = new ProtoElementInjector(null, 0, bindings, isPresent(shadowDomAppInjector));
|
||||
var inj = proto.instantiate(null, null);
|
||||
|
@ -446,7 +447,60 @@ export function main() {
|
|||
expect(inj.get(BindingPropagationConfig)).toEqual(config);
|
||||
});
|
||||
});
|
||||
|
||||
describe("createPrivateComponent", () => {
|
||||
it("should create a private component", () => {
|
||||
var inj = injector([]);
|
||||
inj.createPrivateComponent(SimpleDirective, null);
|
||||
expect(inj.getPrivateComponent()).toBeAnInstanceOf(SimpleDirective);
|
||||
});
|
||||
|
||||
it("should inject parent dependencies into the private component", () => {
|
||||
var inj = parentChildInjectors([SimpleDirective], []);
|
||||
inj.createPrivateComponent(NeedDirectiveFromAncestor, null);
|
||||
expect(inj.getPrivateComponent()).toBeAnInstanceOf(NeedDirectiveFromAncestor);
|
||||
expect(inj.getPrivateComponent().dependency).toBeAnInstanceOf(SimpleDirective);
|
||||
});
|
||||
|
||||
it("should not inject the proxy component into the children of the private component", () => {
|
||||
var injWithPrivateComponent = injector([SimpleDirective]);
|
||||
injWithPrivateComponent.createPrivateComponent(SomeOtherDirective, null);
|
||||
|
||||
var shadowDomProtoInjector = new ProtoElementInjector(null, 0, [NeedDirectiveFromAncestor], false);
|
||||
var shadowDomInj = shadowDomProtoInjector.instantiate(null, injWithPrivateComponent);
|
||||
|
||||
expect(() => shadowDomInj.instantiateDirectives(appInjector, null, defaultPreBuiltObjects)).
|
||||
toThrowError(new RegExp("No provider for SimpleDirective"));
|
||||
});
|
||||
|
||||
it("should inject the private component into the children of the private component", () => {
|
||||
var injWithPrivateComponent = injector([]);
|
||||
injWithPrivateComponent.createPrivateComponent(SimpleDirective, null);
|
||||
|
||||
var shadowDomProtoInjector = new ProtoElementInjector(null, 0, [NeedDirectiveFromAncestor], false);
|
||||
var shadowDomInjector = shadowDomProtoInjector.instantiate(null, injWithPrivateComponent);
|
||||
shadowDomInjector.instantiateDirectives(appInjector, null, defaultPreBuiltObjects);
|
||||
|
||||
expect(shadowDomInjector.get(NeedDirectiveFromAncestor)).toBeAnInstanceOf(NeedDirectiveFromAncestor);
|
||||
expect(shadowDomInjector.get(NeedDirectiveFromAncestor).dependency).toBeAnInstanceOf(SimpleDirective);
|
||||
});
|
||||
|
||||
it("should support rehydrating the private component", () => {
|
||||
var inj = injector([]);
|
||||
inj.createPrivateComponent(DirectiveWithDestroy, new Directive({lifecycle: [onDestroy]}));
|
||||
var dir = inj.getPrivateComponent();
|
||||
|
||||
inj.clearDirectives();
|
||||
|
||||
expect(inj.getPrivateComponent()).toBe(null);
|
||||
expect(dir.onDestroyCounter).toBe(1);
|
||||
|
||||
inj.instantiateDirectives(null, null, null);
|
||||
|
||||
expect(inj.getPrivateComponent()).not.toBe(null);
|
||||
});
|
||||
});
|
||||
|
||||
describe('event emitters', () => {
|
||||
it('should be injectable and callable', () => {
|
||||
var called = false;
|
||||
|
|
Loading…
Reference in New Issue