12 |
13 | Foo
14 | Bar
15 | Baz
16 |
17 |
18 |
19 |
20 | `;
21 |
22 | @Component({
23 | selector: 'my-app',
24 | template: template
25 | })
26 | export class AppComponent { }
27 |
--------------------------------------------------------------------------------
/src/app.states.ts:
--------------------------------------------------------------------------------
1 | import {AppComponent} from "./app.component";
2 | import {Ng2StateDeclaration, loadNgModule} from "@uirouter/angular";
3 |
4 | /** The top level state(s) */
5 | export let MAIN_STATES: Ng2StateDeclaration[] = [
6 | // The top-level app state.
7 | // This state fills the root (defined in index.html) with the AppComponent
8 | { name: 'app', component: AppComponent },
9 |
10 | // This is the Future State for lazy loading the BazModule
11 | { name: 'app.baz.**', url: '/baz', lazyLoad: loadNgModule('src/baz/baz.module') }
12 | ];
13 |
--------------------------------------------------------------------------------
/src/bar/bar.module.ts:
--------------------------------------------------------------------------------
1 | import {UIRouterModule} from "@uirouter/angular";
2 | import {SharedModule} from "../shared.module";
3 | import {BAR_STATES} from "./bar.states";
4 | import {NgModule} from "@angular/core";
5 | import {BarListComponent} from "./barList.component";
6 | import {BarDetailsComponent} from "./barDetail.component";
7 | import {BarFooterComponent} from "./barFooter.component";
8 |
9 | /** The Bar NgModule */
10 | @NgModule({
11 | imports: [
12 | SharedModule,
13 | UIRouterModule.forChild({ states: BAR_STATES })
14 | ],
15 | declarations: [
16 | BarListComponent,
17 | BarDetailsComponent,
18 | BarFooterComponent,
19 | ]
20 | })
21 | export class BarModule { }
22 |
23 |
--------------------------------------------------------------------------------
/src/bar/bar.states.ts:
--------------------------------------------------------------------------------
1 | import {Http} from "@angular/http";
2 | import {BarListComponent} from "./barList.component";
3 | import {BarDetailsComponent} from "./barDetail.component";
4 | import {BarFooterComponent} from "./barFooter.component";
5 | import {Ng2StateDeclaration, Transition} from "@uirouter/angular";
6 | /**
7 | * This file defines the states for the `bar` module.
8 | * The states are exported as an array and imported in the BarModule.
9 | */
10 | export let BAR_STATES: Ng2StateDeclaration[] = [
11 | // A state for the 'app.bar' submodule.
12 | // - Fills in the unnamed ($default) from `app` state with `BarListComponent`
13 | // - Fills in the footer from `app` state with `BarFooterComponent`
14 | // - Fetches barList data using a resolve, then the component displays the data
15 | {
16 | name: 'app.bar',
17 | url: '/bar',
18 | views: {
19 | $default: { component: BarListComponent },
20 | footer: { component: BarFooterComponent }
21 | },
22 | resolve: [
23 | // Inject 'http' and fetch all the bar data
24 | {
25 | token: 'barList',
26 | deps: [Http],
27 | resolveFn: (http: Http) =>
28 | http.get('/data/barData.json').map(res => res.json()).toPromise()
29 | }
30 | ]
31 | },
32 |
33 | // A child state of app.bar
34 | // - This state fills the unnnamed (in `BarListComponent` from `app.foo` state) with `BarDetailsComponent`
35 | // - Has a parameter :barId which appears in the URL
36 | // - Resolves barDetail, then the component displays the data
37 | {
38 | name: 'app.bar.details', url: '/?barId', component: BarDetailsComponent,
39 | resolve: [
40 | // Inject the barList (from the parent) and find the correct
41 | {
42 | token: 'barDetail',
43 | deps: ['barList', Transition],
44 | resolveFn: (barList, trans) =>
45 | barList.find(item => item.id == trans.params().barId)
46 | }
47 | ]
48 | },
49 | ];
50 |
51 |
52 |
--------------------------------------------------------------------------------
/src/bar/barDetail.component.ts:
--------------------------------------------------------------------------------
1 | import {Component, Input} from '@angular/core';
2 |
3 | /**
4 | * This component injects "barDetail" (resolve data) into the matching @Input and renders the detail */
5 | let template = `
6 |
Bar Details
7 |
8 |
9 |
10 |
11 | `;
12 |
13 | @Component({
14 | selector: 'bar-detail',
15 | template: template
16 | })
17 | export class BarDetailsComponent {
18 | // `barDetail` resolve data is provided to this @Input
19 | @Input('barDetail') bar;
20 | }
21 |
--------------------------------------------------------------------------------
/src/bar/barFooter.component.ts:
--------------------------------------------------------------------------------
1 | import {Component, Input} from '@angular/core';
2 |
3 | /**
4 | * This component is shown in the footer when any bar state is active.
5 | * It receives the `barList` resolve data and displays the count of bar objects loaded.
6 | */
7 | @Component({
8 | selector: 'bar-footer',
9 | styles: ['h4 { border-top: 2px solid black; margin-top: 1em; }'],
10 | template: `
Bar Module Active - {{ barList.length }} bars
`
11 | })
12 | export class BarFooterComponent {
13 | @Input() barList;
14 | }
15 |
--------------------------------------------------------------------------------
/src/bar/barList.component.ts:
--------------------------------------------------------------------------------
1 | import {Component, Inject} from '@angular/core';
2 |
3 | /**
4 | * This component has "barList" (resolve data) injected into the constructor.
5 | *
6 | * It creates a list of uiSref (links) to the bar details and highlights the active uiSref
7 | * It provides a viewport for a child state to fill in
8 | */
9 |
10 | let template = `
11 |
18 |
19 |
20 | `;
21 |
22 | @Component({
23 | selector: 'bar',
24 | template: template
25 | })
26 | export class BarListComponent {
27 | // resolve data injected by name 'barList' into 'bars' property
28 | constructor(@Inject("barList") public bars) { }
29 | }
30 |
--------------------------------------------------------------------------------
/src/baz/baz.module.ts:
--------------------------------------------------------------------------------
1 | import {UIRouterModule} from "@uirouter/angular";
2 | import {SharedModule} from "../shared.module";
3 | import {BAZ_STATES} from "./baz.states";
4 | import {NgModule} from "@angular/core";
5 | import {BazListComponent} from "./bazList.component";
6 | import {BazDetailsComponent} from "./bazDetail.component";
7 | import {BazFooterComponent} from "./bazFooter.component";
8 |
9 | /** The Baz NgModule. */
10 | @NgModule({
11 | imports: [
12 | SharedModule,
13 | UIRouterModule.forChild({ states: BAZ_STATES })
14 | ],
15 | declarations: [
16 | BazListComponent,
17 | BazDetailsComponent,
18 | BazFooterComponent,
19 | ]
20 | })
21 | export default class BazModule { }
22 |
--------------------------------------------------------------------------------
/src/baz/baz.states.ts:
--------------------------------------------------------------------------------
1 | import {Http} from "@angular/http";
2 | import {BazListComponent} from "./bazList.component";
3 | import {BazDetailsComponent} from "./bazDetail.component";
4 | import {BazFooterComponent} from "./bazFooter.component";
5 | import {Ng2StateDeclaration, Transition} from "@uirouter/angular";
6 | /**
7 | * This file defines the states for the `baz` module.
8 | * The states are exported as an array and imported in the BazModule.
9 | */
10 | export let BAZ_STATES: Ng2StateDeclaration[] = [
11 |
12 | // A state for the 'app.baz' submodule.
13 | // - Fills in the unnamed ($default) from `app` state with `BazListComponent`
14 | // - Fills in the footer from `app` state with `BazFooterComponent`
15 | // - Fetches bazList data using a resolve, then the component displays the data
16 | {
17 | name: 'app.baz',
18 | url: '/baz',
19 | views: {
20 | $default: { component: BazListComponent },
21 | footer: { component: BazFooterComponent }
22 | },
23 | resolve: [
24 | // Inject 'Http' and fetch all the baz data
25 | {
26 | token: 'bazList',
27 | deps: [Http],
28 | resolveFn: (http: Http) =>
29 | http.get('/data/bazData.json').map(res => res.json()).toPromise()
30 | }
31 | ]
32 | },
33 |
34 | // A child state of app.baz
35 | // - This state fills the unnamed ($default) (in the `AppComponent` from `app` state) with
36 | // `BazDetailsComponent`. This effectively replaces the baz list view with a baz detail view.
37 | // - Has a path parameter :bazId which appears in the URL
38 | // - Resolves bazDetail, then the component displays the data
39 | {
40 | name: 'app.baz.details',
41 | url: '/:bazId',
42 | views: {
43 | '$default@app': { component: BazDetailsComponent }
44 | },
45 | resolve: [
46 | // Inject the bazList (from the parent) and find the correct
47 | {
48 | token: 'bazDetail',
49 | deps: ['bazList', Transition],
50 | resolveFn: (bazList, trans) =>
51 | bazList.find(item => item.id == trans.params().bazId)
52 | }
53 | ]
54 | },
55 | ];
56 |
57 |
58 |
--------------------------------------------------------------------------------
/src/baz/bazDetail.component.ts:
--------------------------------------------------------------------------------
1 | import {Component, Input} from '@angular/core';
2 |
3 | /**
4 | * This component receives `bazDetail` resolve data into the `bazDetail` input, then renders the detail
5 | * It has a link back to the parent state, which is `app.baz`
6 | */
7 | let template = `
8 |
Baz Details
9 | Back to list
10 |
11 |
12 |
13 |
14 | `;
15 |
16 | @Component({
17 | selector: 'baz-detail',
18 | template: template,
19 | // `bazDetail` resolve data is provided to the `bazDetail` input
20 | inputs: ["bazDetail"],
21 | })
22 | export class BazDetailsComponent {
23 | bazDetail;
24 | }
25 |
--------------------------------------------------------------------------------
/src/baz/bazFooter.component.ts:
--------------------------------------------------------------------------------
1 | import {Component, Input} from '@angular/core';
2 |
3 | /**
4 | * This component is shown in the footer when any baz state is active.
5 | * It receives the `bazList` resolve data and displays the count of baz objects loaded.
6 | */
7 | @Component({
8 | selector: 'baz-footer',
9 | styles: ['h4 { border-top: 2px solid black; margin-top: 1em; }'],
10 | template: `
Baz Module Active - {{ bazList.length }} bazs
`
11 | })
12 | export class BazFooterComponent {
13 | @Input() bazList;
14 | }
15 |
--------------------------------------------------------------------------------
/src/baz/bazList.component.ts:
--------------------------------------------------------------------------------
1 | import {Component, Inject} from '@angular/core';
2 |
3 | /**
4 | * This component injects "bazList" (resolve data)
5 | *
6 | * It creates a list of uiSref (links) to the baz details
7 | *
8 | * It does not have a nested viewport because the nested app.baz.details state
9 | * replaces this component with the BazDetailsComponent, using view targeting.
10 | */
11 |
12 | let template = `
13 |
19 | `;
20 |
21 | @Component({
22 | selector: 'baz',
23 | template: template
24 | })
25 | export class BazListComponent {
26 | // resolve data injected by name 'bazList' into 'bazs' property
27 | constructor(@Inject("bazList") public bazs) {
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/bootstrap.ts:
--------------------------------------------------------------------------------
1 | import 'rxjs/add/operator/toPromise';
2 | import 'rxjs/add/operator/map';
3 |
4 | import {platformBrowserDynamic} from '@angular/platform-browser-dynamic';
5 | import {trace, Category, UIRouterModule, UIView} from "@uirouter/angular";
6 | import {NgModule, NgModuleFactoryLoader, SystemJsNgModuleLoader} from "@angular/core";
7 | import {BrowserModule} from "@angular/platform-browser";
8 |
9 | import {MAIN_STATES} from "./app.states";
10 | import {AppComponent} from "./app.component";
11 | import {FooModule} from "./foo/foo.module";
12 | import {BarModule} from "./bar/bar.module";
13 | import {routerConfig} from "./router.config";
14 |
15 | // Enables tracing (check the console) of:
16 | // - TRANSITION transition start, redirect, success, error, ignored
17 | // - VIEWCONFIG ui-view component creation/destruction and viewconfig de/activation
18 | trace.enable(Category.TRANSITION, Category.VIEWCONFIG);
19 |
20 | @NgModule({
21 | imports: [
22 | BrowserModule,
23 | UIRouterModule.forRoot({
24 | states: MAIN_STATES,
25 | otherwise: { state: 'app', params: {} },
26 | useHash: true,
27 | config: routerConfig,
28 | }),
29 | FooModule,
30 | BarModule,
31 | // BazModule will be lazy loaded
32 | ],
33 | declarations: [ AppComponent ],
34 | providers: [
35 | // Provide a NgModule lazy loading strategy
36 | { provide: NgModuleFactoryLoader, useClass: SystemJsNgModuleLoader },
37 | ],
38 | bootstrap: [UIView],
39 | })
40 | class RootModule {}
41 |
42 | platformBrowserDynamic().bootstrapModule(RootModule);
43 |
--------------------------------------------------------------------------------
/src/foo/foo.component.ts:
--------------------------------------------------------------------------------
1 | import {Component} from '@angular/core';
2 |
3 | /**
4 | * This is a simple component which provides two uiSref (links) to two nested states
5 | * and a viewport for the child states to fill in
6 | */
7 | let template = `
8 |
Foo Component
9 |
10 | Nested state 1
11 | Nested state 2
12 |
13 |
14 | `;
15 |
16 | @Component({
17 | selector: 'foo',
18 | template: template
19 | })
20 | export class FooComponent { }
21 |
--------------------------------------------------------------------------------
/src/foo/foo.module.ts:
--------------------------------------------------------------------------------
1 | import {UIRouterModule} from "@uirouter/angular";
2 | import {FOO_STATES} from "./foo.states";
3 | import {SharedModule} from "../shared.module";
4 | import {NgModule} from "@angular/core";
5 | import {FooComponent} from "./foo.component";
6 | import {FooFooterComponent} from "./fooFooter.component";
7 | import {Nest1Component} from "./nest1.component";
8 | import {Nest2Component} from "./nest2.component";
9 |
10 | /** The Foo NgModule */
11 | @NgModule({
12 | imports: [
13 | UIRouterModule.forChild({ states: FOO_STATES }),
14 | SharedModule,
15 | ],
16 | declarations: [
17 | FooComponent,
18 | FooFooterComponent,
19 | Nest1Component,
20 | Nest2Component,
21 | ]
22 | })
23 | export class FooModule { }
24 |
--------------------------------------------------------------------------------
/src/foo/foo.states.ts:
--------------------------------------------------------------------------------
1 | import {FooComponent} from "./foo.component";
2 | import {Nest1Component} from "./nest1.component";
3 | import {Nest2Component} from "./nest2.component";
4 | import {Ng2StateDeclaration} from "@uirouter/angular";
5 | import {FooFooterComponent} from "./fooFooter.component";
6 | /**
7 | * This file defines the states for the `foo` module.
8 | * The states are exported as an array and imported in the FooModule.
9 | */
10 | export let FOO_STATES: Ng2StateDeclaration[] = [
11 | // A state for the 'app.foo' submodule,
12 | // It fills the unnamed ($default) (in the AppComponent from the `app` state) with `FooComponent`
13 | {
14 | name: 'app.foo',
15 | url: '/foo',
16 | views: {
17 | $default: {component: FooComponent},
18 | footer: {component: FooFooterComponent}
19 | }
20 | },
21 |
22 | // A child state of app.foo; it fills the in app.foo with Nest1Component
23 | {
24 | name: 'app.foo.nest1',
25 | url: '/nest1',
26 | component: Nest1Component
27 | },
28 |
29 | // A child state of app.foo; it fills the in app.foo with Nest2Component
30 | {
31 | name: 'app.foo.nest2',
32 | url: '/nest2',
33 | component: Nest2Component
34 | }
35 | ];
36 |
37 |
--------------------------------------------------------------------------------
/src/foo/fooFooter.component.ts:
--------------------------------------------------------------------------------
1 | import {Component} from '@angular/core';
2 |
3 | /**
4 | * This component is shown in the footer when any foo state is active.
5 | */
6 | @Component({
7 | styles: ['h4 { border-top: 1px solid black; margin-top: 2em; }'],
8 | selector: 'foo-footer',
9 | template: `
Foo Module Active
`
10 | })
11 | export class FooFooterComponent { }
12 |
--------------------------------------------------------------------------------
/src/foo/nest1.component.ts:
--------------------------------------------------------------------------------
1 | import {Component} from '@angular/core';
2 |
3 | /**
4 | * This is a simple component used as the component for the app.foo.nest1 state
5 | * to demonstrate grandchildren states
6 | */
7 | let template = `
Nest 1 component
`;
8 |
9 | @Component({
10 | selector: 'nest1',
11 | template: template
12 | })
13 | export class Nest1Component { }
14 |
--------------------------------------------------------------------------------
/src/foo/nest2.component.ts:
--------------------------------------------------------------------------------
1 | import {Component} from '@angular/core';
2 |
3 | /**
4 | * This component demonstrates use of the '#' state parameter, which updates the url hash.
5 | * The '#' parameter is implicitly available.
6 | *
7 | * Note: the parameter value is cleared when clicking a top-level nav link, "Foo", "Bar", "Baz"
8 | * using `{ inherit: false }`
9 | */
10 | let template = `
11 |