Skip to content

Commit

Permalink
feat(di): add support for multi bindings
Browse files Browse the repository at this point in the history
BREAKING CHANGE

Previously a content binding of a component was visible to the directives in its view with the host constraint. This is not the case any more. To access that binding, remove the constraint.
  • Loading branch information
vsavkin committed Sep 3, 2015
1 parent 2fea0c2 commit 7736964
Show file tree
Hide file tree
Showing 9 changed files with 389 additions and 176 deletions.
147 changes: 72 additions & 75 deletions modules/angular2/src/core/compiler/element_injector.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import {
InjectorDynamicStrategy,
BindingWithVisibility
} from 'angular2/src/core/di/injector';
import {resolveBinding, ResolvedFactory} from 'angular2/src/core/di/binding';

import {AttributeMetadata, QueryMetadata} from '../metadata/di';

Expand Down Expand Up @@ -195,70 +196,63 @@ export class DirectiveDependency extends Dependency {
}

export class DirectiveBinding extends ResolvedBinding {
constructor(key: Key, factory: Function, dependencies: Dependency[],
public resolvedBindings: ResolvedBinding[],
public resolvedViewBindings: ResolvedBinding[],
public metadata: RenderDirectiveMetadata) {
super(key, factory, dependencies);
constructor(key: Key, factory: Function, deps: Dependency[],
public metadata: RenderDirectiveMetadata,
public bindings: Array<Type | Binding | any[]>,
public viewBindings: Array<Type | Binding | any[]>) {
super(key, [new ResolvedFactory(factory, deps)], false);
}

get callOnDestroy(): boolean { return this.metadata.callOnDestroy; }

get callOnChanges(): boolean { return this.metadata.callOnChanges; }

get callAfterContentChecked(): boolean { return this.metadata.callAfterContentChecked; }

get displayName(): string { return this.key.displayName; }

get callOnDestroy(): boolean { return this.metadata.callOnDestroy; }

get eventEmitters(): string[] {
return isPresent(this.metadata) && isPresent(this.metadata.events) ? this.metadata.events : [];
}

get changeDetection() { return this.metadata.changeDetection; }

static createFromBinding(binding: Binding, meta: DirectiveMetadata): DirectiveBinding {
if (isBlank(meta)) {
meta = new DirectiveMetadata();
}

var rb = binding.resolve();
var deps = ListWrapper.map(rb.dependencies, DirectiveDependency.createFrom);
var resolvedBindings = isPresent(meta.bindings) ? Injector.resolve(meta.bindings) : [];
var resolvedViewBindings = meta instanceof ComponentMetadata && isPresent(meta.viewBindings) ?
Injector.resolve(meta.viewBindings) :
[];
var rb = resolveBinding(binding);
var rf = rb.resolvedFactories[0];
var deps = rf.dependencies.map(DirectiveDependency.createFrom);
var token = binding.token;
var metadata = RenderDirectiveMetadata.create({
id: stringify(rb.key.token),
id: stringify(binding.token),
type: meta instanceof ComponentMetadata ? RenderDirectiveMetadata.COMPONENT_TYPE :
RenderDirectiveMetadata.DIRECTIVE_TYPE,
selector: meta.selector,
compileChildren: meta.compileChildren,
events: meta.events,
host: isPresent(meta.host) ? MapWrapper.createFromStringMap(meta.host) : null,
properties: meta.properties,
readAttributes: DirectiveBinding._readAttributes(deps),

callOnDestroy: hasLifecycleHook(LifecycleEvent.OnDestroy, rb.key.token, meta),
callOnChanges: hasLifecycleHook(LifecycleEvent.OnChanges, rb.key.token, meta),
callDoCheck: hasLifecycleHook(LifecycleEvent.DoCheck, rb.key.token, meta),
callOnInit: hasLifecycleHook(LifecycleEvent.OnInit, rb.key.token, meta),
callAfterContentInit: hasLifecycleHook(LifecycleEvent.AfterContentInit, rb.key.token, meta),
callAfterContentChecked:
hasLifecycleHook(LifecycleEvent.AfterContentChecked, rb.key.token, meta),
callAfterViewInit: hasLifecycleHook(LifecycleEvent.AfterViewInit, rb.key.token, meta),
callAfterViewChecked: hasLifecycleHook(LifecycleEvent.AfterViewChecked, rb.key.token, meta),
readAttributes: DirectiveBinding._readAttributes(<any>deps),

callOnDestroy: hasLifecycleHook(LifecycleEvent.OnDestroy, token, meta),
callOnChanges: hasLifecycleHook(LifecycleEvent.OnChanges, token, meta),
callDoCheck: hasLifecycleHook(LifecycleEvent.DoCheck, token, meta),
callOnInit: hasLifecycleHook(LifecycleEvent.OnInit, token, meta),
callAfterContentInit: hasLifecycleHook(LifecycleEvent.AfterContentInit, token, meta),
callAfterContentChecked: hasLifecycleHook(LifecycleEvent.AfterContentChecked, token, meta),
callAfterViewInit: hasLifecycleHook(LifecycleEvent.AfterViewInit, token, meta),
callAfterViewChecked: hasLifecycleHook(LifecycleEvent.AfterViewChecked, token, meta),

changeDetection: meta instanceof ComponentMetadata ? meta.changeDetection : null,

exportAs: meta.exportAs
});
return new DirectiveBinding(rb.key, rb.factory, deps, resolvedBindings, resolvedViewBindings,
metadata);
var bindings = isPresent(meta.bindings) ? meta.bindings : [];
var viewBindigs =
meta instanceof ComponentMetadata && isPresent(meta.viewBindings) ? meta.viewBindings : [];
return new DirectiveBinding(rb.key, rf.factory, deps, metadata, bindings, viewBindigs);
}

static _readAttributes(deps) {
static _readAttributes(deps: DirectiveDependency[]): string[] {
var readAttributes = [];
ListWrapper.forEach(deps, (dep) => {
deps.forEach(dep => {
if (isPresent(dep.attributeName)) {
readAttributes.push(dep.attributeName);
}
Expand Down Expand Up @@ -316,7 +310,7 @@ export class ProtoElementInjector {
eventEmitterAccessors: EventEmitterAccessor[][];
protoInjector: ProtoInjector;

static create(parent: ProtoElementInjector, index: number, bindings: ResolvedBinding[],
static create(parent: ProtoElementInjector, index: number, bindings: DirectiveBinding[],
firstBindingIsComponent: boolean, distanceToParent: number,
directiveVariableBindings: Map<string, number>): ProtoElementInjector {
var bd = [];
Expand All @@ -326,43 +320,46 @@ export class ProtoElementInjector {
if (firstBindingIsComponent) {
ProtoElementInjector._createViewBindingsWithVisibility(bindings, bd);
}
ProtoElementInjector._createBindingsWithVisibility(bindings, bd, firstBindingIsComponent);

ProtoElementInjector._createBindingsWithVisibility(bindings, bd);
return new ProtoElementInjector(parent, index, bd, distanceToParent, firstBindingIsComponent,
directiveVariableBindings);
}

private static _createDirectiveBindingWithVisibility(dirBindings: ResolvedBinding[],
private static _createDirectiveBindingWithVisibility(dirBindings: DirectiveBinding[],
bd: BindingWithVisibility[],
firstBindingIsComponent: boolean) {
ListWrapper.forEach(dirBindings, dirBinding => {
dirBindings.forEach(dirBinding => {
bd.push(ProtoElementInjector._createBindingWithVisibility(firstBindingIsComponent, dirBinding,
dirBindings, dirBinding));
});
}

private static _createBindingsWithVisibility(dirBindings: ResolvedBinding[],
bd: BindingWithVisibility[],
firstBindingIsComponent: boolean) {
ListWrapper.forEach(dirBindings, dirBinding => {
ListWrapper.forEach(dirBinding.resolvedBindings, b => {
bd.push(ProtoElementInjector._createBindingWithVisibility(firstBindingIsComponent,
dirBinding, dirBindings, b));
});
private static _createBindingsWithVisibility(dirBindings: DirectiveBinding[],
bd: BindingWithVisibility[]) {
var bindingsFromAllDirectives = [];
dirBindings.forEach(dirBinding => {
bindingsFromAllDirectives =
ListWrapper.concat(bindingsFromAllDirectives, dirBinding.bindings);
});

var resolved = Injector.resolve(bindingsFromAllDirectives);
resolved.forEach(b => bd.push(new BindingWithVisibility(b, Visibility.Public)));
}

private static _createBindingWithVisibility(firstBindingIsComponent, dirBinding, dirBindings,
binding) {
private static _createBindingWithVisibility(firstBindingIsComponent: boolean,
dirBinding: DirectiveBinding,
dirBindings: DirectiveBinding[],
binding: ResolvedBinding) {
var isComponent = firstBindingIsComponent && dirBindings[0] === dirBinding;
return new BindingWithVisibility(binding,
isComponent ? Visibility.PublicAndPrivate : Visibility.Public);
}

private static _createViewBindingsWithVisibility(bindings: ResolvedBinding[],
private static _createViewBindingsWithVisibility(dirBindings: DirectiveBinding[],
bd: BindingWithVisibility[]) {
var db = <DirectiveBinding>bindings[0];
ListWrapper.forEach(db.resolvedViewBindings,
b => bd.push(new BindingWithVisibility(b, Visibility.Private)));
var resolvedViewBindings = Injector.resolve(dirBindings[0].viewBindings);
resolvedViewBindings.forEach(b => bd.push(new BindingWithVisibility(b, Visibility.Private)));
}


Expand Down Expand Up @@ -852,7 +849,6 @@ interface _ElementInjectorStrategy {
isComponentKey(key: Key): boolean;
buildQueries(): void;
addDirectivesMatchingQuery(q: QueryMetadata, res: any[]): void;
getComponentBinding(): DirectiveBinding;
hydrate(): void;
dehydrate(): void;
}
Expand Down Expand Up @@ -953,34 +949,44 @@ class ElementInjectorInlineStrategy implements _ElementInjectorStrategy {
var p = this.injectorStrategy.protoStrategy;

if (p.binding0 instanceof DirectiveBinding) {
this._ei._buildQueriesForDeps(<DirectiveDependency[]>p.binding0.dependencies);
this._ei._buildQueriesForDeps(
<DirectiveDependency[]>p.binding0.resolvedFactories[0].dependencies);
}
if (p.binding1 instanceof DirectiveBinding) {
this._ei._buildQueriesForDeps(<DirectiveDependency[]>p.binding1.dependencies);
this._ei._buildQueriesForDeps(
<DirectiveDependency[]>p.binding1.resolvedFactories[0].dependencies);
}
if (p.binding2 instanceof DirectiveBinding) {
this._ei._buildQueriesForDeps(<DirectiveDependency[]>p.binding2.dependencies);
this._ei._buildQueriesForDeps(
<DirectiveDependency[]>p.binding2.resolvedFactories[0].dependencies);
}
if (p.binding3 instanceof DirectiveBinding) {
this._ei._buildQueriesForDeps(<DirectiveDependency[]>p.binding3.dependencies);
this._ei._buildQueriesForDeps(
<DirectiveDependency[]>p.binding3.resolvedFactories[0].dependencies);
}
if (p.binding4 instanceof DirectiveBinding) {
this._ei._buildQueriesForDeps(<DirectiveDependency[]>p.binding4.dependencies);
this._ei._buildQueriesForDeps(
<DirectiveDependency[]>p.binding4.resolvedFactories[0].dependencies);
}
if (p.binding5 instanceof DirectiveBinding) {
this._ei._buildQueriesForDeps(<DirectiveDependency[]>p.binding5.dependencies);
this._ei._buildQueriesForDeps(
<DirectiveDependency[]>p.binding5.resolvedFactories[0].dependencies);
}
if (p.binding6 instanceof DirectiveBinding) {
this._ei._buildQueriesForDeps(<DirectiveDependency[]>p.binding6.dependencies);
this._ei._buildQueriesForDeps(
<DirectiveDependency[]>p.binding6.resolvedFactories[0].dependencies);
}
if (p.binding7 instanceof DirectiveBinding) {
this._ei._buildQueriesForDeps(<DirectiveDependency[]>p.binding7.dependencies);
this._ei._buildQueriesForDeps(
<DirectiveDependency[]>p.binding7.resolvedFactories[0].dependencies);
}
if (p.binding8 instanceof DirectiveBinding) {
this._ei._buildQueriesForDeps(<DirectiveDependency[]>p.binding8.dependencies);
this._ei._buildQueriesForDeps(
<DirectiveDependency[]>p.binding8.resolvedFactories[0].dependencies);
}
if (p.binding9 instanceof DirectiveBinding) {
this._ei._buildQueriesForDeps(<DirectiveDependency[]>p.binding9.dependencies);
this._ei._buildQueriesForDeps(
<DirectiveDependency[]>p.binding9.resolvedFactories[0].dependencies);
}
}

Expand Down Expand Up @@ -1029,11 +1035,6 @@ class ElementInjectorInlineStrategy implements _ElementInjectorStrategy {
list.push(i.obj9);
}
}

getComponentBinding(): DirectiveBinding {
var p = this.injectorStrategy.protoStrategy;
return <DirectiveBinding>p.binding0;
}
}

/**
Expand Down Expand Up @@ -1086,7 +1087,8 @@ class ElementInjectorDynamicStrategy implements _ElementInjectorStrategy {

for (var i = 0; i < p.bindings.length; i++) {
if (p.bindings[i] instanceof DirectiveBinding) {
this._ei._buildQueriesForDeps(<DirectiveDependency[]>p.bindings[i].dependencies);
this._ei._buildQueriesForDeps(
<DirectiveDependency[]>p.bindings[i].resolvedFactory.dependencies);
}
}
}
Expand All @@ -1104,11 +1106,6 @@ class ElementInjectorDynamicStrategy implements _ElementInjectorStrategy {
}
}
}

getComponentBinding(): DirectiveBinding {
var p = this.injectorStrategy.protoStrategy;
return <DirectiveBinding>p.bindings[0];
}
}

export class QueryError extends BaseException {
Expand Down
Loading

0 comments on commit 7736964

Please sign in to comment.