Stepan Suvorov
Stepan Suvorov

Reputation: 26206

Is there an abstract state in Angular2 Router?

I'm looking for similar solution to ui-router abstract state in Angular2 Router.

To have "virtual" parent state to resolve some common things for child states.

Upvotes: 3

Views: 6653

Answers (2)

Paul Samsotha
Paul Samsotha

Reputation: 209022

A route doesn't need to be associated with a component. It can just have children with an empty path. You can use this "empty" route for things like guards or resolves.

One thing I didn't know until testing right now, is that Resolves (it's data) will trickle down to child routes. So if you want to "resolve some common things for child states", this might be the place to do it.

{
  path: '',
  resolve: {
    data: DummyResolve
  },
  children: [
    { path: 'one', component: Child1Component },
    { path: 'two', component: Child2Component }
  ]
}

Here is the complete test I used to test with

import { Component, Injectable, OnInit } from '@angular/core';
import { Router, Resolve, ActivatedRoute } from '@angular/router';
import { By } from '@angular/platform-browser';
import { Location, CommonModule } from '@angular/common';
import { RouterTestingModule } from '@angular/router/testing';
import { TestBed, inject, fakeAsync, tick, ComponentFixture } from '@angular/core/testing';

@Injectable()
class DummyResolve implements Resolve<string> {
  resolve() {
    return 'Hello Routing';
  }
}

@Component({
  template: `
    <router-outlet></router-outlet>
  `
})
class RoutingComponent {
}

@Component({
  template: `
    <h1>Child One</h1>
    <span>{{ data }}</span>
  `
})
class Child1Component implements OnInit {
  data: string;

  constructor(private route: ActivatedRoute) {}

  ngOnInit() {
    this.route.data.forEach((data: { data: string }) => {
      this.data = data.data;
      console.log(`data from child 1: ${this.data}`);
    });
  }
}

@Component({
  template: `
    <h1>Child Two</h1>
    <span>{{ data }}</span>
  `
})
class Child2Component implements OnInit {
  data: string;

  constructor(private route: ActivatedRoute) {}

  ngOnInit() {
    this.route.data.forEach((data: { data: string }) => {
      this.data = data.data;
      console.log(`data from child 2: ${this.data}`);
    });
  }
}

describe('component: RoutingComponent', function () {
  let fixture: ComponentFixture<RoutingComponent>;

  beforeEach(() => {
    TestBed.configureTestingModule({
      imports: [
        CommonModule,
        RouterTestingModule.withRoutes([
          {
            path: '',
            resolve: {
              data: DummyResolve
            },
            children: [
              { path: 'one', component: Child1Component },
              { path: 'two', component: Child2Component }
            ]
          }
        ])
      ],
      providers: [ DummyResolve ],
      declarations: [ RoutingComponent, Child1Component, Child2Component ]
    });

    fixture = TestBed.createComponent(RoutingComponent);
    fixture.detectChanges();
  });

  it('should go to child one',
    fakeAsync(inject([Router, Location], (router: Router, location: Location) => {

    router.navigate(['/one']);
    tick();
    fixture.detectChanges();
    let debugEl = fixture.debugElement;
    expect(debugEl.query(By.css('h1')).nativeElement.innerHTML).toEqual('Child One');
    expect(debugEl.query(By.css('span')).nativeElement.innerHTML).toEqual('Hello Routing');
  })));

  it('should go to child two',
    fakeAsync(inject([Router, Location], (router: Router, location: Location) => {

    router.navigate(['/two']);
    tick();
    fixture.detectChanges();
    let debugEl = fixture.debugElement;
    expect(debugEl.query(By.css('h1')).nativeElement.innerHTML).toEqual('Child Two');
    expect(debugEl.query(By.css('span')).nativeElement.innerHTML).toEqual('Hello Routing');
  })));
});

Upvotes: 10

Md Ayub Ali Sarker
Md Ayub Ali Sarker

Reputation: 11547

You can add child route like this [app.routeing.ts]

const APP_ROUTES:Routes = [
  {path: '', redirectTo: '/dashboard', pathMatch: 'full'},
  {path: 'report', component: ReportComponent, children: REPORT_ROUTES},
  ];

and child route would be

export const REPORT_ROUTES: RouterConfig = [
  { path: '', component: ReportHomeComponent },
  { path: 'server-report', component: ServerReportComponent } //  report/server-report
  { path: 'client-report', component: ClientReportComponent }  //  report/client-report
];

Upvotes: 1

Related Questions