feat: allow for forward references in injection
It is possible for a class defined first to be referencing a class defined later, and as a result at the time of the definition it is not possible to access the later's class reference. This allows to refer to the later defined class through a closure.Closes #1891
This commit is contained in:
@ -0,0 +1,6 @@
|
||||
/// This file contains tests that make sense only in Dart
|
||||
library angular2.test.core.forward_ref_integration_spec;
|
||||
|
||||
main() {
|
||||
// Don't run in Dart as it is not relevant, and Dart const rules prevent us from expressing it.
|
||||
}
|
84
modules/angular2/test/core/forward_ref_integration_spec.es6
Normal file
84
modules/angular2/test/core/forward_ref_integration_spec.es6
Normal file
@ -0,0 +1,84 @@
|
||||
import {
|
||||
AsyncTestCompleter,
|
||||
beforeEach,
|
||||
ddescribe,
|
||||
describe,
|
||||
expect,
|
||||
iit,
|
||||
inject,
|
||||
it,
|
||||
xit
|
||||
} from 'angular2/test_lib';
|
||||
import {TestBed} from 'angular2/src/test_lib/test_bed';
|
||||
import {Directive, Component} from 'angular2/src/core/annotations_impl/annotations';
|
||||
import {Query} from 'angular2/src/core/annotations_impl/di';
|
||||
import {View} from 'angular2/src/core/annotations_impl/view';
|
||||
import {QueryList, NgFor} from 'angular2/angular2';
|
||||
import {Inject} from 'angular2/src/di/annotations_impl';
|
||||
import {forwardRef, resolveForwardRef, bind} from 'angular2/di';
|
||||
import {Type} from 'angular2/src/facade/lang';
|
||||
|
||||
export function main() {
|
||||
describe("forwardRef integration", function () {
|
||||
it('should instantiate components which are declared using forwardRef', inject(
|
||||
[TestBed, AsyncTestCompleter],
|
||||
(tb, async) => {
|
||||
tb.createView(App).then((view) => {
|
||||
view.detectChanges();
|
||||
expect(view.rootNodes).toHaveText('frame(lock)');
|
||||
async.done();
|
||||
});
|
||||
})
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'app',
|
||||
injectables: [
|
||||
forwardRef(() => Frame)
|
||||
]
|
||||
})
|
||||
@View({
|
||||
template: `<door><lock></lock></door>`,
|
||||
directives: [
|
||||
bind(forwardRef(() => Door)).toClass(forwardRef(() => Door)),
|
||||
bind(forwardRef(() => Lock)).toClass(forwardRef(() => Lock))
|
||||
]
|
||||
})
|
||||
class App {
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'Lock'
|
||||
})
|
||||
@View({
|
||||
directives: [NgFor],
|
||||
template: `{{frame.name}}(<span *ng-for="var lock of locks">{{lock.name}}</span>)`
|
||||
})
|
||||
class Door {
|
||||
locks: QueryList;
|
||||
frame: Frame;
|
||||
|
||||
constructor(@Query(forwardRef(() => Lock)) locks: QueryList, @Inject(forwardRef(() => Frame)) frame:Frame) {
|
||||
this.frame = frame;
|
||||
this.locks = locks;
|
||||
}
|
||||
}
|
||||
|
||||
class Frame {
|
||||
name: string;
|
||||
constructor() {
|
||||
this.name = 'frame';
|
||||
}
|
||||
}
|
||||
|
||||
@Directive({
|
||||
selector: 'lock'
|
||||
})
|
||||
class Lock {
|
||||
name: string;
|
||||
constructor() {
|
||||
this.name = 'lock';
|
||||
}
|
||||
}
|
23
modules/angular2/test/di/forward_ref_spec.js
vendored
Normal file
23
modules/angular2/test/di/forward_ref_spec.js
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
import {
|
||||
AsyncTestCompleter,
|
||||
beforeEach,
|
||||
ddescribe,
|
||||
describe,
|
||||
expect,
|
||||
iit,
|
||||
inject,
|
||||
it,
|
||||
xit,
|
||||
} from 'angular2/test_lib';
|
||||
import {forwardRef, resolveForwardRef} from 'angular2/di';
|
||||
import {Type} from 'angular2/src/facade/lang';
|
||||
|
||||
export function main() {
|
||||
describe("forwardRef", function () {
|
||||
it('should wrap and unwrap the reference', () => {
|
||||
var ref = forwardRef(() => String);
|
||||
expect(ref instanceof Type).toBe(true);
|
||||
expect(resolveForwardRef(ref)).toBe(String);
|
||||
});
|
||||
});
|
||||
}
|
23
modules/angular2/test/di/injector_spec.js
vendored
23
modules/angular2/test/di/injector_spec.js
vendored
@ -1,6 +1,6 @@
|
||||
import {isBlank, BaseException} from 'angular2/src/facade/lang';
|
||||
import {describe, ddescribe, it, iit, expect, beforeEach} from 'angular2/test_lib';
|
||||
import {Injector, bind, ResolvedBinding} from 'angular2/di';
|
||||
import {Injector, bind, ResolvedBinding, Key, forwardRef} from 'angular2/di';
|
||||
import {Optional, Inject, InjectLazy} from 'angular2/src/di/annotations_impl';
|
||||
|
||||
|
||||
@ -382,13 +382,32 @@ export function main() {
|
||||
});
|
||||
|
||||
describe('resolve', function() {
|
||||
it('should resolve and flatten', function() {
|
||||
it('should resolve and flatten', () => {
|
||||
var bindings = Injector.resolve([Engine, [BrokenEngine]]);
|
||||
bindings.forEach(function(b) {
|
||||
if (isBlank(b)) return; // the result is a sparse array
|
||||
expect(b instanceof ResolvedBinding).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
it('should resolve forward references', () => {
|
||||
var bindings = Injector.resolve([
|
||||
forwardRef(() => Engine),
|
||||
[ bind(forwardRef(() => BrokenEngine)).toClass(forwardRef(() => Engine)) ],
|
||||
bind(forwardRef(() => String)).toFactory(() => 'OK', [forwardRef(() => Engine)]),
|
||||
bind(forwardRef(() => DashboardSoftware)).toAsyncFactory(() => 123, [forwardRef(() => BrokenEngine)])
|
||||
]);
|
||||
|
||||
var engineBinding = bindings[Key.get(Engine).id];
|
||||
var brokenEngineBinding = bindings[Key.get(BrokenEngine).id];
|
||||
var stringBinding = bindings[Key.get(String).id];
|
||||
var dashboardSoftwareBinding = bindings[Key.get(DashboardSoftware).id];
|
||||
|
||||
expect(engineBinding.factory() instanceof Engine).toBe(true);
|
||||
expect(brokenEngineBinding.factory() instanceof Engine).toBe(true);
|
||||
expect(stringBinding.dependencies[0].key).toEqual(Key.get(Engine));
|
||||
expect(dashboardSoftwareBinding.dependencies[0].key).toEqual(Key.get(BrokenEngine));
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
Reference in New Issue
Block a user