1

I want to provide a set of generic components, so they will be not aware of services that provides dependencies. Dependencies such components are promises. In other words I want to keep for instance data access out of the scope of those generic components. Any dependencies, especially data to render and component configuration should be provided to components by the context that are declaring the component. This is easy when I declare component in view as a DOM tag e.g.:

<generic-component data="getSomeData()" configuration="componentConfig"></generic-component>

But how I can handle that when component is invoked directly be the route?

I've read very similar issue but answer for the question definitely did not satisfy me. Accepted answer advice to put dependencies into component, but that means losing generic manner of component.

In Angular 1 approach to do so was by using resolve property of route declaration. What is equivalent of Angular's 1 resolve in Angular 2?

Please refer to the mentioned question's example cause it's very accurate.

Community
  • 1
  • 1

2 Answers2

1

Angular 2 in RC 4 introduced resolve property of Route.

This property is object with properties which implements Resolve interface.

Each resolver must be @Injectable and has method resolve which return Observable|Promise|any.

When You inject ActivatedRoute as route into component You can access each resolved property from route.snapshod.data['someResolveKey'].

Example from angular.io doc:

class Backend {
  fetchTeam(id: string) {
    return 'someTeam';
  }
}
@Injectable()
class TeamResolver implements Resolve<Team> {
  constructor(private backend: Backend) {}
  resolve(
    route: ActivatedRouteSnapshot,
    state: RouterStateSnapshot
  ): Observable<any>|Promise<any>|any {
    return this.backend.fetchTeam(route.params.id);
  }
}
@NgModule({
  imports: [
    RouterModule.forRoot([
      {
        path: 'team/:id',
        component: TeamCmp,
        resolve: {
          team: TeamResolver
        }
      }
    ])
  ],
  providers: [TeamResolver]
})
class AppModule {}

Or You can also provide a function with the same signature instead of the class.

@NgModule({
  imports: [
    RouterModule.forRoot([
      {
        path: 'team/:id',
        component: TeamCmp,
        resolve: {
          team: 'teamResolver'
        }
      }
    ])
  ],
  providers: [
    {
      provide: 'teamResolver',
      useValue: (route: ActivatedRouteSnapshot, state: RouterStateSnapshot) => 'team'
    }
  ]
})
class AppModule {}

And You can get data in component:

export class SomeComponent implements OnInit {
    resource : string;
    team : string;

    constructor(private route: ActivatedRoute) {
    }

    ngOnInit() {
        this.team = this.route.snapshot.data['team'];

        // UPDATE: ngOnInit will be fired once,
        // even If you use same component for different routes.
        // If You want to rebind data when You change route
        // You should not use snapshot but subscribe on
        // this.route.data or this.route.params eg.:
        this.route.params.subscribe((params: Params) => this.resource = params['resource']);
        this.route.data.subscribe((data: any) => this.team = data['team']);
    }

}

Hope it helps, happy hacking!

Hakier
  • 505
  • 2
  • 13
0

I experience exactly the same issue.

Route's dedicated components which will holds generics components could be solutions. But this is not elegant, it is rather bypass then solution.

aniaw
  • 1