Skip to content

Commit 9df20f0

Browse files
fix(README): Update bootstrap directions to avoid 'digest already in progress' errors
1 parent dc418cc commit 9df20f0

File tree

4 files changed

+87
-4755
lines changed

4 files changed

+87
-4755
lines changed

README.md

Lines changed: 41 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@ $stateProvider.state({
3434
template: '<h1>Other</h1>', // AngularJS template/controller
3535
controller: function($scope) { /* do stuff */ }
3636
})
37-
3837
```
3938

4039
When routing to an Angular component, that component uses the standard
@@ -70,20 +69,19 @@ We need to use manual AngularJS bootstrapping mode.
7069

7170
#### Add AngularJS module `ui.router.upgrade`
7271

73-
- Add 'ui.router.upgrade' to your AngularJS app module's depedencies
72+
* Add 'ui.router.upgrade' to your AngularJS app module's depedencies
7473

7574
```js
76-
let ng1module = angular.module("myApp", ['ui.router', 'ui.router.upgrade']);
75+
let ng1module = angular.module('myApp', ['ui.router', 'ui.router.upgrade']);
7776
```
7877

7978
[_example_](https://github.com/ui-router/sample-app-angular-hybrid/blob/e4b1144d5e3e3451f0f0cc640175bb7055294fdd/app/bootstrap/ngmodule.ts#L21-L25)
8079

8180
#### Create a root Angular NgModule
8281

83-
- Import the `BrowserModule`, `UpgradeModule`, and a `UIRouterUpgradeModule.forChild()` module.
84-
- Add `providers` entry for any AngularJS services you want to expose to Angular.
85-
- The module should have a `ngDoBootstrap` method which calls the `UpgradeModule`'s `bootstrap` method.
86-
82+
* Import the `BrowserModule`, `UpgradeModule`, and a `UIRouterUpgradeModule.forChild()` module.
83+
* Add `providers` entry for any AngularJS services you want to expose to Angular.
84+
* The module should have a `ngDoBootstrap` method which calls the `UpgradeModule`'s `bootstrap` method.
8785

8886
```js
8987
export function getDialogService($injector) {
@@ -112,36 +110,42 @@ export function getDialogService($injector) {
112110

113111
[_example_](https://github.com/ui-router/sample-app-angular-hybrid/blob/e4b1144d5e3e3451f0f0cc640175bb7055294fdd/app/bootstrap/bootstrap.ts#L63-L73)
114112

115-
116113
#### Defer intercept
117114

118115
Tell UI-Router that it should wait until all bootstrapping is complete before doing the initial URL synchronization.
119116

120117
```js
121-
ngmodule.config([ '$urlServiceProvider', ($urlService: UrlService) => $urlService.deferIntercept() ]);
118+
ngmodule.config(['$urlServiceProvider', ($urlService: UrlService) => $urlService.deferIntercept()]);
122119
```
123120

124121
[_example_](https://github.com/ui-router/sample-app-angular-hybrid/blob/e4b1144d5e3e3451f0f0cc640175bb7055294fdd/app/bootstrap/bootstrap.ts#L75-L76)
125122

126-
127123
#### Bootstrap the app
128124

129-
- Bootstrap Angular
130-
- Angular runs ngDoBootstrap() which bootstraps AngularJS
131-
- Chain off `bootstrapModule()` and tell UIRouter to synchronize the URL and listen for further URL changes
125+
* Bootstrap Angular
126+
* Angular runs ngDoBootstrap() which bootstraps AngularJS
127+
* Chain off `bootstrapModule()` and tell UIRouter to synchronize the URL and listen for further URL changes
128+
* Do this in the Angular Zone to avoid "digest already in progress" errors.
132129

133130
```js
134131
// Wait until the DOM is ready
135-
angular.element(document).ready(function () {
132+
angular.element(document).ready(function() {
136133
// Manually bootstrap the Angular app
137-
platformBrowserDynamic().bootstrapModule(SampleAppModule).then(platformRef => {
138-
// get() UrlService from DI (this call will create all the UIRouter services)
139-
const url: UrlService = platformRef.injector.get(UrlService);
140-
141-
// Instruct UIRouter to listen to URL changes
142-
url.listen();
143-
url.sync();
144-
});
134+
platformBrowserDynamic()
135+
.bootstrapModule(SampleAppModule)
136+
.then(platformRef => {
137+
// get() UrlService from DI (this call will create all the UIRouter services)
138+
const url: UrlService = platformRef.injector.get(UrlService);
139+
140+
// Instruct UIRouter to listen to URL changes
141+
function startUIRouter() {
142+
url.listen();
143+
url.sync();
144+
}
145+
146+
const ngZone: NgZone = platformRef.injector.get(NgZone);
147+
ngZone.run(startUIRouter);
148+
});
145149
});
146150
```
147151

@@ -188,25 +192,23 @@ $stateProvider.state(leaf);
188192
@NgModule({
189193
imports: [
190194
UIRouterUpgradeModule.forChild({
191-
states: [featureState1, featureState2]
192-
})
195+
states: [featureState1, featureState2],
196+
}),
193197
],
194-
declarations: [FeatureComponent1, FeatureComponent2]
198+
declarations: [FeatureComponent1, FeatureComponent2],
195199
})
196200
export class MyFeatureModule {}
197201
```
198202

199203
[_example_](https://github.com/ui-router/sample-app-angular-hybrid/blob/e4b1144d5e3e3451f0f0cc640175bb7055294fdd/app/prefs/index.ts#L11-L22)
200204

201205
Add the feature module to the root NgModule imports
206+
202207
```js
203208
@NgModule({
204-
imports: [
205-
BrowserModule,
206-
UIRouterUpgradeModule,
207-
MyFeatureModule
208-
]
209-
}) class SampleAppModule {}
209+
imports: [BrowserModule, UIRouterUpgradeModule, MyFeatureModule],
210+
})
211+
class SampleAppModule {}
210212
```
211213

212214
[_example_](https://github.com/ui-router/sample-app-angular-hybrid/blob/e4b1144d5e3e3451f0f0cc640175bb7055294fdd/app/bootstrap/bootstrap.ts#L64)
@@ -216,12 +218,10 @@ Note: You can also add states directly to the root NgModule using `UIRouterModul
216218
```js
217219
@NgModule({
218220
// import the Ng1ToNg2Module and create a UIRouter "child module"
219-
imports: [
220-
BrowserModule,
221-
UIRouterUpgradeModule.forChild({ states: NG2_STATES })
222-
],
223-
declarations: [NG2_COMPONENTS]
224-
}) class SampleAppModule {}
221+
imports: [BrowserModule, UIRouterUpgradeModule.forChild({ states: NG2_STATES })],
222+
declarations: [NG2_COMPONENTS],
223+
})
224+
class SampleAppModule {}
225225
```
226226

227227
### Limitations:
@@ -244,9 +244,10 @@ export function ng2StateOnEnter(transition: Transition, svc: MyService) {
244244
}
245245
ng2StateOnEnter.$inject = [Transition, 'MyService'];
246246
export const NG2_STATE = {
247-
name: 'ng2state', url: '/ng2state',
248-
onEnter: ng2StateOnEnter
249-
}
247+
name: 'ng2state',
248+
url: '/ng2state',
249+
onEnter: ng2StateOnEnter,
250+
};
250251
```
251252

252253
# Examples
@@ -265,4 +266,3 @@ https://stackblitz.com/github/ui-router/sample-app-angular-hybrid/tree/angular-c
265266
Version 2.0.0 of `@uirouter/angular-hybrid` only supports `UpgradeAdapter`, which works fine but is no longer in development.
266267
Version 30.0+ of `@uirouter/angular-hybrid` only supports `UpgradeModule` from `@angular/upgrade/static`, which is what the Angular team actively supports for hybrid mode.
267268
Because we dropped support for `UpgradeAdapter`, current users of `@uirouter/angular-hybrid` 2.x will have to switch to `UpgradeModule` when upgrading to 3.x.
268-

example/package.json

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,8 @@
33
"scripts": {
44
"start": "webpack-dev-server --open",
55
"build": "webpack",
6-
"test": "run-s build e2e",
7-
"test-ui": "run-s build e2e-ui",
8-
"e2e": "run-p -r browser-sync cypress",
9-
"e2e-ui": "run-p -r browser-sync cypress-ui",
10-
"browser-sync": "browser-sync start --port 4000 --server . --no-open",
11-
"cypress": "wait-on tcp:4000 && cypress run",
12-
"cypress-ui": "wait-on tcp:4000 && cypress open"
6+
"test": "npm run build && cypress-runner run --path .",
7+
"test:ui": "npm run build && cypress-runner open --path ."
138
},
149
"dependencies": {
1510
"@angular/common": "^5.0.0",
@@ -30,9 +25,6 @@
3025
"webpack-dev-server": "2.9.6"
3126
},
3227
"devDependencies": {
33-
"browser-sync": "^2.23.6",
34-
"cypress": "^1.4.2",
35-
"npm-run-all": "^4.1.2",
36-
"wait-on": "^2.1.0"
28+
"@uirouter/cypress-runner": "^1.0.4"
3729
}
3830
}

example/src/main.ts

Lines changed: 43 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,73 +1,72 @@
11
import * as angular from 'angular';
2-
import { Component, NgModule } from '@angular/core';
2+
import { Component, NgModule, NgZone } from '@angular/core';
33
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
44
import { UpgradeModule } from '@angular/upgrade/static';
55
import { BrowserModule } from '@angular/platform-browser';
66
import { UIRouterUpgradeModule, NgHybridStateDeclaration } from '@uirouter/angular-hybrid';
7-
import { UrlService} from '@uirouter/core';
8-
7+
import { UrlService } from '@uirouter/core';
98

109
const app = angular.module('minimal', ['ui.router.upgrade']);
1110

1211
app.run(($stateRegistry, $urlService) => {
13-
$urlService.rules.initial({state: 'app'});
12+
$urlService.rules.initial({ state: 'app' });
1413

1514
$stateRegistry.register({
16-
url: '',
17-
name: 'app',
18-
template: `
15+
url: '',
16+
name: 'app',
17+
template: `
1918
<a ui-sref=".ng1" ui-sref-active-eq="active">app.ng1</a>
2019
<a ui-sref=".ng1.ng2" ui-sref-active-eq="active">app.ng1.ng2</a>
2120
<a ui-sref=".ng2" ui-sref-active-eq="active">app.ng2</a>
2221
<a ui-sref=".ng2.ng2" ui-sref-active-eq="active">app.ng2.ng2</a>
2322
<ui-view></ui-view>
24-
`
23+
`,
2524
});
2625

2726
// route to ng1 component
2827
$stateRegistry.register({
29-
url: '/ng1',
30-
name: 'app.ng1',
31-
component: 'ng1Component',
28+
url: '/ng1',
29+
name: 'app.ng1',
30+
component: 'ng1Component',
3231
});
3332

3433
// nested route to ng2 component
3534
$stateRegistry.register({
36-
url: '/ng2',
37-
name: 'app.ng1.ng2',
38-
component: Ng2Component,
35+
url: '/ng2',
36+
name: 'app.ng1.ng2',
37+
component: Ng2Component,
3938
});
4039

4140
// route to ng2 component
4241
$stateRegistry.register({
43-
url: '/ng2',
44-
name: 'app.ng2',
45-
component: Ng2Component,
42+
url: '/ng2',
43+
name: 'app.ng2',
44+
component: Ng2Component,
4645
});
4746
});
4847

4948
// An AngularJS component
5049
app.component('ng1Component', {
51-
template: `
50+
template: `
5251
<h1>ng1 component</h1>
5352
<a ui-sref="app">Back to app</a>
5453
<ui-view></ui-view>
5554
`,
56-
controller: function() {
57-
this.$onInit = function() {
58-
console.log('ng1Component.$onInit()');
59-
}
60-
}
55+
controller: function() {
56+
this.$onInit = function() {
57+
console.log('ng1Component.$onInit()');
58+
};
59+
},
6160
});
6261

6362
// An Angular component
6463
@Component({
65-
selector: 'ng2-component',
66-
template: `
64+
selector: 'ng2-component',
65+
template: `
6766
<h1>ng2 component</h1>
6867
<a uiSref="app">Back to app</a>
6968
<ui-view></ui-view>
70-
`
69+
`,
7170
})
7271
export class Ng2Component {
7372
ngOnInit() {
@@ -78,7 +77,7 @@ export class Ng2Component {
7877
const nestedState: NgHybridStateDeclaration = {
7978
url: '/ng2',
8079
name: 'app.ng2.ng2',
81-
component: Ng2Component
80+
component: Ng2Component,
8281
};
8382

8483
// The root Angular module
@@ -92,7 +91,8 @@ const nestedState: NgHybridStateDeclaration = {
9291
],
9392
declarations: [Ng2Component],
9493
entryComponents: [Ng2Component],
95-
}) export class RootModule {
94+
})
95+
export class RootModule {
9696
constructor(private upgrade: UpgradeModule) {}
9797
ngDoBootstrap() {
9898
// The DOM must be already be available
@@ -102,14 +102,21 @@ const nestedState: NgHybridStateDeclaration = {
102102

103103
// Using AngularJS config block, call `deferIntercept()`.
104104
// This tells UI-Router to delay the initial URL sync (until all bootstrapping is complete)
105-
app.config([ '$urlServiceProvider', $urlService => $urlService.deferIntercept() ]);
105+
app.config(['$urlServiceProvider', $urlService => $urlService.deferIntercept()]);
106106

107107
// Manually bootstrap the Angular app
108-
platformBrowserDynamic().bootstrapModule(RootModule).then(platformRef => {
109-
// get() UrlService from DI (this call will create all the UIRouter services)
110-
const url: UrlService = platformRef.injector.get(UrlService);
108+
platformBrowserDynamic()
109+
.bootstrapModule(RootModule)
110+
.then(platformRef => {
111+
// get() UrlService from DI (this call will create all the UIRouter services)
112+
const url: UrlService = platformRef.injector.get(UrlService);
111113

112-
// Instruct UIRouter to listen to URL changes
113-
url.listen();
114-
url.sync();
115-
});
114+
// Instruct UIRouter to listen to URL changes
115+
function startUIRouter() {
116+
url.listen();
117+
url.sync();
118+
}
119+
120+
const ngZone: NgZone = platformRef.injector.get(NgZone);
121+
ngZone.run(startUIRouter);
122+
});

0 commit comments

Comments
 (0)