Skip to content

Commit d3bd332

Browse files
fix(ng2.NgModule): Allow apps with no forChild modules
fix(ResolveContext): Scope native injector in resolve tree. - Build injector() using scoped native injector refactor(ng2.NgModule): Switch from NG2_INJECTOR_TOKEN to NATIVE_INJECTOR_TOKEN - Move token to core Closes #3009
1 parent 88c6494 commit d3bd332

File tree

6 files changed

+44
-42
lines changed

6 files changed

+44
-42
lines changed

src/ng2/directives/uiView.ts

+2-3
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,8 @@ import {
77
import {UIRouter} from "../../router";
88
import {trace} from "../../common/trace";
99
import {ViewContext, ViewConfig, ActiveUIView} from "../../view/interface";
10-
import {NG2_INJECTOR_TOKEN} from "../interface";
1110
import {Ng2ViewConfig} from "../statebuilders/views";
12-
import {ResolveContext} from "../../resolve/resolveContext";
11+
import {ResolveContext, NATIVE_INJECTOR_TOKEN} from "../../resolve/resolveContext";
1312
import {flattenR} from "../../common/common";
1413
import {MergeInjector} from "../mergeInjector";
1514

@@ -227,7 +226,7 @@ export class UIView {
227226
newProviders.push({ provide: UIView.PARENT_INJECT, useValue: parentInject });
228227

229228
let parentComponentInjector = this.viewContainerRef.injector;
230-
let moduleInjector = context.getResolvable(NG2_INJECTOR_TOKEN).data;
229+
let moduleInjector = context.getResolvable(NATIVE_INJECTOR_TOKEN).data;
231230
let mergedParentInjector = new MergeInjector(moduleInjector, parentComponentInjector);
232231

233232
return ReflectiveInjector.resolveAndCreate(newProviders, mergedParentInjector);

src/ng2/lazyLoadNgModule.ts

+6-6
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
/** @module ng2 */ /** */
22
import {NgModuleFactoryLoader, NgModuleRef, Injector, NgModuleFactory} from "@angular/core";
33

4-
import {NG2_INJECTOR_TOKEN} from "./interface";
54
import {LazyLoadResult} from "../state/interface";
65

76
import {Transition} from "../transition/transition";
8-
import {RootModule, ChildModule, UIROUTER_ROOT_MODULE, UIROUTER_CHILD_MODULE} from "./uiRouterNgModule";
7+
import {RootModule, StatesModule, UIROUTER_ROOT_MODULE, UIROUTER_MODULE_TOKEN} from "./uiRouterNgModule";
98
import {applyModuleConfig} from "./uiRouterConfig";
109
import {UIRouter} from "../router";
1110
import {Resolvable} from "../resolve/resolvable";
11+
import {NATIVE_INJECTOR_TOKEN} from "../resolve/resolveContext";
1212

1313
/**
1414
* Returns a function which lazy loads a nested module
@@ -27,7 +27,7 @@ import {Resolvable} from "../resolve/resolvable";
2727
export function loadNgModule(path: string): (transition: Transition) => Promise<LazyLoadResult> {
2828
/** Get the parent NgModule Injector (from resolves) */
2929
const getNg2Injector = (transition: Transition) =>
30-
transition.injector().getAsync(NG2_INJECTOR_TOKEN);
30+
transition.injector().getAsync(NATIVE_INJECTOR_TOKEN);
3131

3232
/**
3333
* Lazy loads the NgModule using the NgModuleFactoryLoader
@@ -70,16 +70,16 @@ export function loadNgModule(path: string): (transition: Transition) => Promise<
7070
throw new Error('Lazy loaded modules should not contain a UIRouterModule.forRoot() module');
7171
}
7272

73-
let childModules: ChildModule[] = injector.get(UIROUTER_CHILD_MODULE);
74-
childModules.forEach(module => applyModuleConfig(uiRouter, injector, module));
73+
let modules: StatesModule[] = injector.get(UIROUTER_MODULE_TOKEN);
74+
modules.forEach(module => applyModuleConfig(uiRouter, injector, module));
7575

7676
let replacementState = uiRouter.stateRegistry.get(originalName);
7777
if (replacementState === originalState) {
7878
throw new Error(`The module that was loaded from ${path} should have a ui-router state named '${originalName}'`);
7979
}
8080

8181
// Supply the newly loaded states with the Injector from the lazy loaded NgModule
82-
replacementState.$$state().resolvables.push(Resolvable.fromData(NG2_INJECTOR_TOKEN, injector));
82+
replacementState.$$state().resolvables.push(Resolvable.fromData(NATIVE_INJECTOR_TOKEN, injector));
8383

8484
return {};
8585
}

src/ng2/providers.ts

+6-5
Original file line numberDiff line numberDiff line change
@@ -95,14 +95,15 @@ import {UrlRouter} from "../url/urlRouter";
9595
import {ViewService} from "../view/view";
9696
import {UIView, ParentUIViewInject} from "./directives/uiView";
9797
import {ng2ViewsBuilder, Ng2ViewConfig} from "./statebuilders/views";
98-
import {Ng2ViewDeclaration, NG2_INJECTOR_TOKEN} from "./interface";
98+
import {Ng2ViewDeclaration} from "./interface";
9999
import {applyRootModuleConfig, applyModuleConfig} from "./uiRouterConfig";
100100
import {Globals} from "../globals";
101101
import {UIRouterLocation} from "./location";
102102
import {services} from "../common/coreservices";
103103
import {Resolvable} from "../resolve/resolvable";
104-
import {RootModule, ChildModule, UIROUTER_ROOT_MODULE, UIROUTER_CHILD_MODULE} from "./uiRouterNgModule";
104+
import {RootModule, StatesModule, UIROUTER_ROOT_MODULE, UIROUTER_MODULE_TOKEN} from "./uiRouterNgModule";
105105
import {UIRouterRx} from "./rx";
106+
import {NATIVE_INJECTOR_TOKEN} from "../resolve/resolveContext";
106107

107108
/**
108109
* This is a factory function for a UIRouter instance
@@ -115,7 +116,7 @@ let uiRouterFactory = (
115116
injector: Injector) => {
116117

117118
let rootModules: RootModule[] = injector.get(UIROUTER_ROOT_MODULE);
118-
let childModules: ChildModule[] = injector.get(UIROUTER_CHILD_MODULE);
119+
let modules: StatesModule[] = injector.get(UIROUTER_MODULE_TOKEN);
119120

120121
if (rootModules.length !== 1) {
121122
throw new Error("Exactly one UIRouterModule.forRoot() should be in the bootstrapped app module's imports: []");
@@ -144,7 +145,7 @@ let uiRouterFactory = (
144145
registry.stateQueue.flush(router.stateService);
145146

146147
// Prep the tree of NgModule by placing the root NgModule's Injector on the root state.
147-
let ng2InjectorResolvable = Resolvable.fromData(NG2_INJECTOR_TOKEN, injector);
148+
let ng2InjectorResolvable = Resolvable.fromData(NATIVE_INJECTOR_TOKEN, injector);
148149
registry.root().resolvables.push(ng2InjectorResolvable);
149150

150151

@@ -154,7 +155,7 @@ let uiRouterFactory = (
154155

155156
setTimeout(() => {
156157
rootModules.forEach(moduleConfig => applyRootModuleConfig(router, injector, moduleConfig));
157-
childModules.forEach(moduleConfig => applyModuleConfig(router, injector, moduleConfig));
158+
modules.forEach(moduleConfig => applyModuleConfig(router, injector, moduleConfig));
158159

159160
// Start monitoring the URL
160161
if (!router.urlRouterProvider.interceptDeferred) {

src/ng2/uiRouterConfig.ts

+2-4
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
/** @module ng2 */ /** */
22
import {UIRouter} from "../router";
3-
import {ChildModule, RootModule} from "./uiRouterNgModule";
3+
import {StatesModule, RootModule} from "./uiRouterNgModule";
44
import {Injector} from "@angular/core";
55
import {isDefined} from "../common/predicates";
66

7-
export function applyModuleConfig(uiRouter: UIRouter, injector: Injector, options: ChildModule) {
7+
export function applyModuleConfig(uiRouter: UIRouter, injector: Injector, options: StatesModule) {
88
if (options.configClass) {
99
injector.get(options.configClass);
1010
}
@@ -29,8 +29,6 @@ export function applyRootModuleConfig(uiRouter: UIRouter, injector: Injector, co
2929
uiRouter.urlRouterProvider.otherwise(<any> config.otherwise);
3030
}
3131
}
32-
33-
applyModuleConfig(uiRouter, injector, config);
3432
}
3533

3634

src/ng2/uiRouterNgModule.ts

+11-12
Original file line numberDiff line numberDiff line change
@@ -110,31 +110,30 @@ export class UIRouterModule {
110110
* @param module UI-Router module options
111111
* @returns an `NgModule`
112112
*/
113-
static forChild(module: ChildModule = {}): ModuleWithProviders {
113+
static forChild(module: StatesModule = {}): ModuleWithProviders {
114114
return {
115115
ngModule: UIRouterModule,
116116
providers: UIRouterModule.makeProviders(module, false),
117117
}
118118
}
119119

120-
static makeProviders(module: ChildModule, forRoot: boolean): Provider[] {
121-
let provideConfig: Provider[] = [module.configClass]
120+
static makeProviders(module: StatesModule, forRoot: boolean): Provider[] {
121+
let providers: Provider[] = [module.configClass]
122122
.filter(identity)
123123
.map(configClass => ({ provide: configClass, useClass: configClass }));
124124

125-
let UIROUTER_MODULE_TOKEN = forRoot ? UIROUTER_ROOT_MODULE : UIROUTER_CHILD_MODULE;
125+
if (forRoot) providers.push({ provide: UIROUTER_ROOT_MODULE, useValue: module, multi: true});
126+
providers.push({ provide: UIROUTER_MODULE_TOKEN, useValue: module, multi: true });
127+
providers.push({ provide: ANALYZE_FOR_ENTRY_COMPONENTS, useValue: module.states || [], multi: true });
126128

127-
return provideConfig.concat([
128-
{ provide: UIROUTER_MODULE_TOKEN, useValue: module, multi: true },
129-
{ provide: ANALYZE_FOR_ENTRY_COMPONENTS, useValue: module.states || [], multi: true },
130-
]);
129+
return providers;
131130
}
132131
}
133132

134133
/**
135134
* UI-Router declarative configuration which can be provided to [[UIRouterModule.forRoot]]
136135
*/
137-
export interface RootModule extends ChildModule {
136+
export interface RootModule extends StatesModule {
138137
/**
139138
* Chooses a `LocationStrategy`.
140139
*
@@ -162,7 +161,7 @@ export interface RootModule extends ChildModule {
162161
/**
163162
* UI-Router Module declarative configuration which can be passed to [[UIRouterModule.forChild]]
164163
*/
165-
export interface ChildModule {
164+
export interface StatesModule {
166165
/**
167166
* The module's UI-Router states
168167
*
@@ -214,6 +213,6 @@ export interface ChildModule {
214213
configClass?: Type<any>;
215214
}
216215

217-
export const UIROUTER_ROOT_MODULE = new OpaqueToken("UIRouter Module Root Options");
218-
export const UIROUTER_CHILD_MODULE = new OpaqueToken("UIRouter Module Options");
216+
export const UIROUTER_ROOT_MODULE = new OpaqueToken("UIRouter Root Module");
217+
export const UIROUTER_MODULE_TOKEN = new OpaqueToken("UIRouter Module");
219218

src/resolve/resolveContext.ts

+17-12
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
import { find, tail, uniqR, unnestR, inArray } from "../common/common";
33
import {propEq} from "../common/hof";
44
import {trace} from "../common/trace";
5-
import {services} from "../common/coreservices";
5+
import {services, $InjectorLike} from "../common/coreservices";
66
import {resolvePolicies, PolicyWhen} from "./interface";
77

88
import {PathNode} from "../path/node";
@@ -13,10 +13,12 @@ import {stringify} from "../common/strings";
1313
import {Transition} from "../transition/transition";
1414
import {UIInjector} from "../common/interface";
1515

16-
var when = resolvePolicies.when;
16+
const when = resolvePolicies.when;
1717
const ALL_WHENS = [when.EAGER, when.LAZY];
1818
const EAGER_WHENS = [when.EAGER];
1919

20+
export const NATIVE_INJECTOR_TOKEN = "Native Injector";
21+
2022
/**
2123
* Encapsulates Depenency Injection for a path of nodes
2224
*
@@ -28,6 +30,7 @@ const EAGER_WHENS = [when.EAGER];
2830
* The ResolveContext closes over the [[PathNode]]s, and provides DI for the last node in the path.
2931
*/
3032
export class ResolveContext {
33+
_injector: UIInjector;
3134

3235
constructor(private _path: PathNode[]) { }
3336

@@ -131,7 +134,7 @@ export class ResolveContext {
131134
}
132135

133136
injector(): UIInjector {
134-
return new UIInjectorImpl(this);
137+
return this._injector || (this._injector = new UIInjectorImpl(this));
135138
}
136139

137140
findNode(resolvable: Resolvable): PathNode {
@@ -147,16 +150,16 @@ export class ResolveContext {
147150
let node = this.findNode(resolvable);
148151
// Find which other resolvables are "visible" to the `resolvable` argument
149152
// subpath stopping at resolvable's node, or the whole path (if the resolvable isn't in the path)
150-
var subPath: PathNode[] = PathFactory.subPath(this._path, x => x === node) || this._path;
151-
var availableResolvables: Resolvable[] = subPath
153+
let subPath: PathNode[] = PathFactory.subPath(this._path, x => x === node) || this._path;
154+
let availableResolvables: Resolvable[] = subPath
152155
.reduce((acc, node) => acc.concat(node.resolvables), []) //all of subpath's resolvables
153156
.filter(res => res !== resolvable); // filter out the `resolvable` argument
154157

155158
const getDependency = (token: any) => {
156159
let matching = availableResolvables.filter(r => r.token === token);
157160
if (matching.length) return tail(matching);
158161

159-
let fromInjector = services.$injector.get(token);
162+
let fromInjector = this.injector().get(token);
160163
if (!fromInjector) {
161164
throw new Error("Could not find Dependency Injection token: " + stringify(token));
162165
}
@@ -169,7 +172,12 @@ export class ResolveContext {
169172
}
170173

171174
class UIInjectorImpl implements UIInjector {
172-
constructor(public context: ResolveContext) { }
175+
native: $InjectorLike;
176+
177+
constructor(public context: ResolveContext) {
178+
this.native = this.get(NATIVE_INJECTOR_TOKEN) || services.$injector;
179+
}
180+
173181
get(token: any) {
174182
var resolvable = this.context.getResolvable(token);
175183
if (resolvable) {
@@ -178,15 +186,12 @@ class UIInjectorImpl implements UIInjector {
178186
}
179187
return resolvable.data;
180188
}
181-
return services.$injector.get(token);
189+
return this.native && this.native.get(token);
182190
}
183191

184192
getAsync(token: any) {
185193
var resolvable = this.context.getResolvable(token);
186194
if (resolvable) return resolvable.get(this.context);
187-
return services.$q.when(services.$injector.get(token));
195+
return services.$q.when(this.native.get(token));
188196
}
189-
190-
/** The native injector ($injector on ng1, Root Injector on ng2, justjs injector for everything else) */
191-
native = services.$injector;
192197
}

0 commit comments

Comments
 (0)