Angular2 using @Inputs with <router-outlet>s

TypescriptAngularAngular2 Template

Typescript Problem Overview


I have a sub-navigation in my page that displays some subviews below a common main view. I would like to pass an object to the subviews through the <router-outlet> so that I can retrieve the data once in the main component and just share it with my sub components.

Note: If I include the directive <one></one> in the main.html it works but this isn't my desired behavior.

Main View:

<h1>Details</h1>   
<a [router-link]="['./sub1']">One</a> | 
<a [router-link]="['./sub2']">Two</a> | 
<a [router-link]="['./sub3']">Three</a>   
<hr/>  
<router-outlet [data]="maindata"></router-outlet>

Sub View 1:

<h2>{{ data.name }}</h2>
...

Main View:

@Component({
	selector: 'main-detail',
	directives: [ROUTER_DIRECTIVES],
	templateUrl: './main.html'
})
@RouteConfig([
	{ path: '/', redirectTo: '/one' },
	{ path: '/one', as: 'One', component: OneComponent },
	{ path: '/two', as: 'Two', component: TwoComponent },
	{ path: '/three', as: 'Three', component: ThreeComponent }
])
export class MainComponent {
	maindata: Object = {name:'jim'};
}

Sub View 1:

@Component({
	selector: 'one',
	directives: [CORE_DIRECTIVES],
	inputs: ['data'],
	templateUrl: './one.html'
})
export class OneComponent {
	@Input() data;
}

Typescript Solutions


Solution 1 - Typescript

If it's simple data you can pass them through RouteParams

<a [router-link]="['./sub3'],{name:'jim'}">Three</a>

then in your sub view

@Component({
    selector: 'one',
    directives: [CORE_DIRECTIVES],
    templateUrl: './one.html'
})
export class OneComponent {
    data: any;
  constructor(params: RouteParams){
    this.data = params.get('data');
  }
}

You can also setup the route to always pass params from the component by moving the RouterConfig INSIDE the component (Note, this is not how it's normally done):

export class AppCmp {
  history: string[] = [];
  constructor(public list: PersonalizationList,
              private router_: Router) {
    list.get('histoy', (response) => {
      this.history = response;
    });
    router_.config([
      { path: '/', component: HomeCmp, as: 'Home', data: this.history },
      { path: '/about', component: AboutCmp, as: 'About' }
    ]);
  }
}

Credit to the Source

If you are going to do something more complex I suggest using a service to communicate between routes/components. It's actually the way I prefer to do it.

Sample Service:

import {Injectable} from 'angular2/angular2';

@Injectable()
export class CarsService {
  list1: array<any> = ['a','b','c','d'];
  list2: array<any>;

  constructor() {
  	this.list2 = [1,2,3,9,11];
  }
}

How you Inject a service:

export class Cars {
  constructor(cars:CarsService) {
    this.cmpList1 = cars.list1;
    this.cmpList2 = cars.list2;
  }
}

This way you can use the service to communicate regardless of parent/child or other weird restrictions.

Solution 2 - Typescript

Looks like syntax has been changed. Below works for me ~Angular4.0.0

HTML (Pass Route Parameters)

<li><a [routerLink]="['/templatecreate',{mode:'New'}]">New Job</a></li>

Component

constructor(private route: ActivatedRoute) { }

ngOnInit() {       
  this.getTemplate();
    
  this.sub = this.route.params.subscribe(params => { this.id = params['mode'];
  console.log("Routing Mode", this.id);    
  });
}

Solution 3 - Typescript

I think the proper Angular2 way to be passing data is via Dependency Injections (by using a Service) otherwise the user will be able to see the data you're passing in the browser's URL.

Also, using a Service will allow for "Separation of Concerns", meaning that Component A shouldn't be dependent on Component B.

Dependency Injection Links:

  1. https://angular.io/guide/dependency-injection

  2. https://angular.io/guide/dependency-injection-in-action

  3. https://www.youtube.com/watch?v=MJrw43GP2u0

Solution 4 - Typescript

We have a big angular project (just starting with Angular, so solutions are as good as our understanding :-) ).

The shell component can call any of the 4 (route-based) "action" modules - where each module has its own service (but no component view) and can call any of the 6 (route-based) shared Components. The shared components are shared between all 4 services, so they cannot have any logic specific to the calling module.

We are using a service resolver ActionModuleServiceResolver which DIs all 4 action services. Based on state (RouterStateSnapshot) URL, we return the appropriate service.

@Injectable()
export class ActionModuleServiceResolver implements Resolve<ActionModuleService> {

  constructor(private _mod1: ModOneService,
    private _mod2: ModTwoService, private _mod3: ModThreeService,private _mod4: ModFourService) { }

  resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): ActionModuleService {
    if(state.url.includes(`/${ActionModuleType.ModOne}/`))
      return this._mod1;
    else if(state.url.includes(`/${ActionModuleType.ModTwo}/`))
      return this._mod2;
....
else
  return null;
  }
}

Each Action Module's Routing module routes to the shared component like this:

    const routes: Routes = [
  {
    path: 'sharedMod1', component: SharedModOneComponent, data: {
      title: `ModOne_SharedModOne`,
      routeName: 'sharedMod1'
    }, resolve: { actionModule: ActionModuleServiceResolver }
  },

Next, each SharedModule gets the activated route via DI and gets the calling service:

//SharedModOne.component.ts
constructor(protected route: ActivatedRoute) {}

  ngOnInit() {
    this.actionModSvc= this.route.snapshot.data['actionModule'];
    this.actionModSvc.getDesignFile(this.route);
  }

Hope this helps someone, also if this can be improved, please let me know.

Thanks,

RDV

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionJRulleView Question on Stackoverflow
Solution 1 - TypescriptDennis SmolekView Answer on Stackoverflow
Solution 2 - TypescriptTanmayView Answer on Stackoverflow
Solution 3 - TypescriptGeneView Answer on Stackoverflow
Solution 4 - TypescriptRDVView Answer on Stackoverflow