Skip to content

Commit 4ce27c9

Browse files
BC-BREAK: Major breaking changes for angular 2 bootstrap between beta.2 and beta.3
- Removed `@UIRouterModule` decorator. - Added `UIRouterModule.forRoot()` and `UIRouterModule.forChild()` factory methods @NgModule({ imports: [ UIRouterModule.forRoot({ states: INITIAL_STATES, useHash: true, configClass: MyUIRouterConfig }), BrowserModule, FeatureModule, ], declarations: INITIAL_COMPONENTS }) class RootAppModule {} @NgModule({ imports: [ UIRouterModule.forChild({ states: FEATURE_STATES, configClass: FeatureConfig }), CommonModule, ], declarations: FEATURE_COMPONENTS })
1 parent 4c3a390 commit 4ce27c9

File tree

9 files changed

+340
-317
lines changed

9 files changed

+340
-317
lines changed

package.json

+5-5
Original file line numberDiff line numberDiff line change
@@ -56,11 +56,11 @@
5656
},
5757
"license": "MIT",
5858
"devDependencies": {
59-
"@angular/common": "^2.0.0-rc.7",
60-
"@angular/compiler": "^2.0.0-rc.7",
61-
"@angular/core": "^2.0.0-rc.7",
62-
"@angular/platform-browser": "^2.0.0-rc.7",
63-
"@angular/platform-browser-dynamic": "^2.0.0-rc.7",
59+
"@angular/common": "^2.0.0",
60+
"@angular/compiler": "^2.0.0",
61+
"@angular/core": "^2.0.0",
62+
"@angular/platform-browser": "^2.0.0",
63+
"@angular/platform-browser-dynamic": "^2.0.0",
6464
"babel-core": "^5.8.14",
6565
"clone": "^1.0.2",
6666
"conventional-changelog": "^1.1.0",

src/ng2.ts

-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ export * from "./ng2/providers";
1414
export * from "./ng2/location";
1515
export * from "./ng2/directives/directives";
1616
export * from "./ng2/statebuilders/views";
17-
export * from "./ng2/statebuilders/lazyLoadNgModuleResolvable";
1817
export * from "./ng2/uiRouterNgModule";
1918
export * from "./ng2/uiRouterConfig";
2019

src/ng2/lazyLoadNgModule.ts

+39-20
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
11
/** @module ng2 */ /** */
2-
import {Transition} from "../transition/transition";
3-
import {NG2_INJECTOR_TOKEN, Ng2StateDeclaration} from "./interface";
4-
import {UIROUTER_STATES_TOKEN} from "./uiRouterNgModule";
5-
62
import {NgModuleFactoryLoader, NgModuleRef, Injector, NgModuleFactory} from "@angular/core";
7-
import {unnestR} from "../common/common";
3+
4+
import {NG2_INJECTOR_TOKEN} from "./interface";
85
import {LazyLoadResult} from "../state/interface";
96

7+
import {Transition} from "../transition/transition";
8+
import {RootModule, ChildModule, UIROUTER_ROOT_MODULE, UIROUTER_CHILD_MODULE} from "./uiRouterNgModule";
9+
import {applyModuleConfig} from "./uiRouterConfig";
10+
import {UIRouter} from "../router";
11+
import {Resolvable} from "../resolve/resolvable";
12+
1013
/**
1114
* Returns a function which lazy loads a nested module
1215
*
@@ -39,7 +42,9 @@ export function loadNgModule(path: string): (transition: Transition) => Promise<
3942
factory.create(ng2Injector));
4043

4144
/**
42-
* Apply the Lazy Loaded NgModule's Injector to the newly loaded state tree.
45+
* Apply the UI-Router Modules found in the lazy loaded module.
46+
*
47+
* Apply the Lazy Loaded NgModule's newly created Injector to the right state in the state tree.
4348
*
4449
* Lazy loading uses a placeholder state which is removed (and replaced) after the module is loaded.
4550
* The NgModule should include a state with the same name as the placeholder.
@@ -48,24 +53,38 @@ export function loadNgModule(path: string): (transition: Transition) => Promise<
4853
* The NgModule's Injector (and ComponentFactoryResolver) will be added to that state.
4954
* The Injector/Factory are used when creating Components for the `replacement` state and all its children.
5055
*/
51-
function applyNgModuleToNewStates(transition: Transition, ng2Module: NgModuleRef<any>): LazyLoadResult {
52-
var targetName = transition.to().name;
53-
let newStates: Ng2StateDeclaration[] = ng2Module.injector.get(UIROUTER_STATES_TOKEN).reduce(unnestR, []);
54-
let replacementState = newStates.find(state => state.name === targetName);
55-
56-
if (!replacementState) {
57-
throw new Error(`The module that was loaded from ${path} should have a state named '${targetName}'` +
58-
`, but it only had: ${(newStates || []).map(s=>s.name).join(', ')}`);
56+
function loadUIRouterModules(transition: Transition, ng2Module: NgModuleRef<any>): LazyLoadResult {
57+
let injector = ng2Module.injector;
58+
let parentInjector = <Injector> ng2Module.injector['parent'];
59+
let uiRouter: UIRouter = injector.get(UIRouter);
60+
61+
let originalName = transition.to().name;
62+
let originalState = uiRouter.stateRegistry.get(originalName);
63+
64+
let rootModules: RootModule[] = injector.get(UIROUTER_ROOT_MODULE);
65+
let parentRootModules: RootModule[] = parentInjector.get(UIROUTER_ROOT_MODULE);
66+
let newRootModules = rootModules.filter(module => parentRootModules.indexOf(module) === -1);
67+
68+
if (newRootModules.length) {
69+
console.log(rootModules);
70+
throw new Error('Lazy loaded modules should not contain a UIRouterModule.forRoot() module');
71+
}
72+
73+
let childModules: ChildModule[] = injector.get(UIROUTER_CHILD_MODULE);
74+
childModules.forEach(module => applyModuleConfig(uiRouter, injector, module));
75+
76+
let replacementState = uiRouter.stateRegistry.get(originalName);
77+
if (replacementState === originalState) {
78+
throw new Error(`The module that was loaded from ${path} should have a ui-router state named '${originalName}'`);
5979
}
60-
61-
// Add the injector as a resolve.
62-
replacementState['_ngModuleInjector'] = ng2Module.injector;
6380

64-
// Return states to be registered by the lazyLoadHook
65-
return { states: newStates };
81+
// Supply the newly loaded states with the Injector from the lazy loaded NgModule
82+
replacementState.$$state().resolvables.push(Resolvable.fromData(NG2_INJECTOR_TOKEN, injector));
83+
84+
return {};
6685
}
6786

6887
return (transition: Transition) => getNg2Injector(transition)
6988
.then((injector: Injector) => createNg2Module(path, injector))
70-
.then((moduleRef: NgModuleRef<any>) => applyNgModuleToNewStates(transition, moduleRef))
89+
.then((moduleRef: NgModuleRef<any>) => loadUIRouterModules(transition, moduleRef))
7190
}

src/ng2/providers.ts

+59-80
Original file line numberDiff line numberDiff line change
@@ -17,66 +17,74 @@
1717
* - Create application states (as defined by [[Ng2StateDeclaration]]).
1818
*
1919
* ```js
20-
* export let state1 = {
20+
* export let state1: Ng2StateDeclaration = {
2121
* name: 'state1',
2222
* component: State1Component,
2323
* url: '/one'
2424
* }
2525
*
26-
* export let state2 = {
26+
* export let state2: Ng2StateDeclaration = {
2727
* name: 'state2',
2828
* component: State2Component,
2929
* url: '/two'
3030
* }
3131
* ```
3232
*
33-
* - Create application feature modules using [[UIRouterModule]]
33+
* - Import a [[UIRouterModule.forChild]] module into your feature `NgModule`s.
3434
*
3535
* ```js
36-
* @ UIRouterModule({
37-
* imports: [ CommonModule ],
38-
* states: [ state1, state2 ]
36+
* @ NgModule({
37+
* imports: [
38+
* SharedModule,
39+
* UIRouterModule.forChild({ states: [state1, state2 ] })
40+
* ],
41+
* declarations: [
42+
* State1Component,
43+
* State2Component,
44+
* ]
3945
* })
4046
* export class MyFeatureModule {}
4147
* ```
4248
*
43-
* - Optionally create a [[UIRouterConfig]] to perform any pre-bootstrap configuration.
49+
* - Import a [[UIRouterModule.forRoot]] module into your application root `NgModule`
50+
* - Either bootstrap a [[UIView]] component, or add a `<ui-view></ui-view>` viewport to your root component.
4451
*
4552
* ```js
46-
* import {UIRouter} from "ui-router-ng2";
53+
* @ NgModule({
54+
* imports: [
55+
* BrowserModule,
56+
* UIRouterModule.forRoot({ states: [ homeState ] }),
57+
* MyFeatureModule,
58+
* ],
59+
* declarations: [
60+
* HomeComponent
61+
* ]
62+
* bootstrap: [ UIView ]
63+
* })
64+
* class RootAppModule {}
4765
*
48-
* @ Injectable()
49-
* export class MyUIRouterConfig {
50-
* constructor() {} // Constructor is injectable
51-
* configure(uiRouter: UIRouter) {
52-
* uiRouter.urlRouterProvider.otherwise(() => uiRouter.stateService.target('home'));
53-
* }
54-
* }
66+
* browserPlatformDynamic.bootstrapModule(RootAppModule);
5567
* ```
5668
*
57-
* - When bootstrapping the root module: use the [[provideUIRouter]] function:
58-
* - Either bootstrap a [[UIView]] component, or add a `<ui-view></ui-view>` viewport to your root component.
69+
* - Optionally specify a configuration class [[ChildModule.configClass]] for any module
70+
* to perform any router configuration during bootstrap or lazyload.
71+
* Pass the class to [[UIRouterModule.forRoot]] or [[UIRouterModule.forChild]].
5972
*
6073
* ```js
61-
* import {platformBrowserDynamic} from '@angular/platform-browser-dynamic';
62-
* import {UIRouterModule, provideUIRouter, UIView} from "ui-router-ng2";
63-
* import {MyUIRouterConfig} from "./router.config";
64-
*
65-
* @ UIRouterModule({
66-
* import: [ FeatureModule, BrowserModule ],
67-
* providers: [ provideUIRouter({ configClass: MyUIRouterConfig }) ],
68-
* states: [ homeState ],
69-
* bootstrap: [ UIView ]
70-
* })
71-
* class RootAppModule {}
74+
* import {UIRouter} from "ui-router-ng2";
7275
*
73-
* platformBrowserDynamic().bootstrapModule(RootAppModule);
76+
* @ Injectable()
77+
* export class MyUIRouterConfig {
78+
* // Constructor is injectable
79+
* constructor(uiRouter: UIRouter) {
80+
* uiRouter.urlMatcherFactory.type('datetime', myDateTimeParamType);
81+
* }
82+
* }
7483
* ```
7584
*
7685
* @preferred @module ng2
7786
*/ /** */
78-
import {Injector, OpaqueToken, Provider} from "@angular/core";
79-
import {ClassProvider, ExistingProvider, FactoryProvider, TypeProvider, ValueProvider} from "@angular/core"; // has or is using
87+
import {Injector, Provider} from "@angular/core";
8088
import {UIRouter} from "../router";
8189
import {PathNode} from "../path/node";
8290
import {StateRegistry} from "../state/stateRegistry";
@@ -88,24 +96,31 @@ import {ViewService} from "../view/view";
8896
import {UIView, ParentUIViewInject} from "./directives/uiView";
8997
import {ng2ViewsBuilder, Ng2ViewConfig} from "./statebuilders/views";
9098
import {Ng2ViewDeclaration, NG2_INJECTOR_TOKEN} from "./interface";
91-
import {UIRouterConfig} from "./uiRouterConfig";
99+
import {applyRootModuleConfig, applyModuleConfig} from "./uiRouterConfig";
92100
import {Globals} from "../globals";
93101
import {UIRouterLocation} from "./location";
94102
import {services} from "../common/coreservices";
95103
import {Resolvable} from "../resolve/resolvable";
96-
import {ngModuleResolvablesBuilder} from "./statebuilders/lazyLoadNgModuleResolvable";
97-
import {flattenR} from "../common/common";
98-
import {UIROUTER_STATES_TOKEN} from "./uiRouterNgModule";
104+
import {RootModule, ChildModule, UIROUTER_ROOT_MODULE, UIROUTER_CHILD_MODULE} from "./uiRouterNgModule";
99105
import {UIRouterRx} from "./rx";
100-
import {LocationStrategy, HashLocationStrategy, PathLocationStrategy} from "@angular/common";
101106

102107
/**
103108
* This is a factory function for a UIRouter instance
104109
*
105110
* Creates a UIRouter instance and configures it for Angular 2, then invokes router bootstrap.
106111
* This function is used as an Angular 2 `useFactory` Provider.
107112
*/
108-
let uiRouterFactory = (routerConfig: UIRouterConfig, location: UIRouterLocation, injector: Injector) => {
113+
let uiRouterFactory = (
114+
location: UIRouterLocation,
115+
injector: Injector) => {
116+
117+
let rootModules: RootModule[] = injector.get(UIROUTER_ROOT_MODULE);
118+
let childModules: ChildModule[] = injector.get(UIROUTER_CHILD_MODULE);
119+
120+
if (rootModules.length !== 1) {
121+
throw new Error("Exactly one UIRouterModule.forRoot() should be in the bootstrapped app module's imports: []");
122+
}
123+
109124
// ----------------- Monkey Patches ----------------
110125
// Monkey patch the services.$injector to the ng2 Injector
111126
services.$injector.get = injector.get.bind(injector);
@@ -127,7 +142,6 @@ let uiRouterFactory = (routerConfig: UIRouterConfig, location: UIRouterLocation,
127142

128143
// Apply statebuilder decorator for ng2 NgModule registration
129144
registry.stateQueue.flush(router.stateService);
130-
registry.decorator('resolvables', ngModuleResolvablesBuilder);
131145

132146
// Prep the tree of NgModule by placing the root NgModule's Injector on the root state.
133147
let ng2InjectorResolvable = Resolvable.fromData(NG2_INJECTOR_TOKEN, injector);
@@ -139,13 +153,8 @@ let uiRouterFactory = (routerConfig: UIRouterConfig, location: UIRouterLocation,
139153
registry.stateQueue.autoFlush(router.stateService);
140154

141155
setTimeout(() => {
142-
// Let the app apply custom configuration...
143-
// (global transition hooks, deferIntercept, otherwise, etc)
144-
routerConfig.configure(router);
145-
146-
// Register the states from the root NgModule [[UIRouterModule]]
147-
let states = injector.get(UIROUTER_STATES_TOKEN, []).reduce(flattenR, []);
148-
states.forEach(state => registry.register(state));
156+
rootModules.forEach(moduleConfig => applyRootModuleConfig(router, injector, moduleConfig));
157+
childModules.forEach(moduleConfig => applyModuleConfig(router, injector, moduleConfig));
149158

150159
// Start monitoring the URL
151160
if (!router.urlRouterProvider.interceptDeferred) {
@@ -158,55 +167,25 @@ let uiRouterFactory = (routerConfig: UIRouterConfig, location: UIRouterLocation,
158167
};
159168

160169
export const _UIROUTER_INSTANCE_PROVIDERS: Provider[] = [
161-
{ provide: UIRouter, useFactory: uiRouterFactory, deps: [UIRouterConfig, UIRouterLocation, Injector] },
170+
{ provide: UIRouter, useFactory: uiRouterFactory, deps: [UIRouterLocation, Injector] },
162171
{ provide: UIRouterLocation, useClass: UIRouterLocation },
172+
{ provide: UIView.PARENT_INJECT, useFactory: (r: StateRegistry) => { return { fqn: null, context: r.root() } as ParentUIViewInject }, deps: [StateRegistry]},
163173
];
164174

165-
export const _UIROUTER_PROVIDERS: Provider[] = [
175+
export const _UIROUTER_SERVICE_PROVIDERS: Provider[] = [
166176
{ provide: StateService, useFactory: (r: UIRouter) => r.stateService , deps: [UIRouter]},
167177
{ provide: TransitionService, useFactory: (r: UIRouter) => r.transitionService, deps: [UIRouter]},
168178
{ provide: UrlMatcherFactory, useFactory: (r: UIRouter) => r.urlMatcherFactory, deps: [UIRouter]},
169179
{ provide: UrlRouter, useFactory: (r: UIRouter) => r.urlRouter , deps: [UIRouter]},
170180
{ provide: ViewService, useFactory: (r: UIRouter) => r.viewService , deps: [UIRouter]},
171181
{ provide: StateRegistry, useFactory: (r: UIRouter) => r.stateRegistry , deps: [UIRouter]},
172182
{ provide: Globals, useFactory: (r: UIRouter) => r.globals , deps: [UIRouter]},
173-
174-
{ provide: UIView.PARENT_INJECT, useFactory: (r: StateRegistry) => { return { fqn: null, context: r.root() } as ParentUIViewInject }, deps: [StateRegistry]}
175183
];
176184

177-
/**
178-
* Provides an Instance of UI-Router for NG2.
179-
*
180-
* Use this on the root NgModule to configure and create an instance of the Angular 2 UIRouter.
181-
*
182-
* @example
183-
* ```js
184-
*
185-
* @ UIRouterModule({
186-
* states: [ homeState, aboutState ],
187-
* providers: [ provideUIRouter({ configClass: MyUIRouterConfig, useHash: true }) ],
188-
* bootstrap: [ UIView ]
189-
* }) class RootNgModule {}
190-
*
191-
* platformBrowserDynamic().bootstrapModule(RootNgModule);
192-
* ```
193-
*
194-
* Note: UIRouter should only be provided *once*, on the root module, when bootstrapping the application.
195-
*/
196-
export function provideUIRouter(rootConfig: { configClass?: typeof UIRouterConfig, useHash?: boolean } = {}) {
197-
// Provide the UIRouter instance providers
198-
return _UIROUTER_INSTANCE_PROVIDERS.concat(
199-
// Provide the user-supplied UIRouterConfig class, or use base UIRouterConfig (as a no-op config)
200-
{ provide: UIRouterConfig, useClass: (rootConfig.configClass as any || UIRouterConfig) },
201-
// Provide the PathLocationStrategy by default unless `useHash` is `true`
202-
{ provide: LocationStrategy, useClass: (rootConfig.useHash ? HashLocationStrategy : PathLocationStrategy ) }
203-
);
204-
}
205-
206185
/**
207186
* The UI-Router providers, for use in your application bootstrap
208187
*
209-
* @deprecated use [[UIRouterModule]] and [[provideUIRouter]]
188+
* @deprecated use [[UIRouterModule.forRoot]]
210189
*/
211-
export const UIROUTER_PROVIDERS: Provider[] = _UIROUTER_INSTANCE_PROVIDERS.concat(_UIROUTER_PROVIDERS);
190+
export const UIROUTER_PROVIDERS: Provider[] = _UIROUTER_INSTANCE_PROVIDERS.concat(_UIROUTER_SERVICE_PROVIDERS);
212191

src/ng2/statebuilders/lazyLoadNgModuleResolvable.ts

-21
This file was deleted.

0 commit comments

Comments
 (0)