14
votes

In angular 1.*, I was using ui-router and was able to pass NON URL Parameters from one state to another. By NON URL Parameter, I mean passing some parameters that does NOT appear on the URL (so completely transparent for the user).

The way to do this in Angular 1.* was by defining a state like this (stateToRedirect is the non-url parameter)

   $stateProvider
    .state('LOGIN_STATE', {
      url: `login`,
      component: 'login',
      params: {
        stateToRedirect: 'home'
      }
    });

And changing state like this:

  $state.go('LOGIN_STATE', {
    stateToRedirect: 'OTHER_STATE',
  });

In the LOGIN_STATE, I was able to access this parameter doing this:

$stateParams.stateToRedirect;

I'm trying to find the same behaviour for Angular 2 Router, my understanding is that Angular 2 Router has improved a lot and we might not need to use ui-router-ng2.

So my question is: How do you reproduce the above behaviour in Angular 2 Router ?

This question seemed to be what I wanted but I don't want paramter in the URL and the 'data' property on the route seems good but I can't find documentation on how to set it dynamically.

5

5 Answers

11
votes

The question you are asking is more about component to component communication rather than routing per se. What you require is to pass data from one component (associated with a particular route), to another component (associated with another route).

Component to component communication can be achieved in the following ways

  1. Components having parent-child relationship can pass data via @Input() and @Output() decorators and event emitters

  2. Via the use of a service. Components not sharing a parent-child relationship residing in the same module can share data via services, either via the use of Observable sequences (having a producer-consumer model) or by setting data in variables and read accordingly. This method can be extended to components residing in different modules by registering the service with the root (or parent to both) module.

  3. Via the router. Data can be passed via the router as path parameters eg: my/path/thisisapathvalue, optional parameters (using matrix notation), eg my/path;item=hello;item2=world or via query string paramters eg my/path?item=hello&item2=world. You can also resolve data for a particular component by using resolve guards which either resolve static data, data retrieved from a server, resolved via functions etc.

For your scenario, what you most likely need is a Service which communicates data between your source component to the destination component, since even by using resolve guards to resolve the data, you're going to need an additional service to temporary store the data that you need to pass.

2
votes

It is possible to do this using a route resolver, it will be a little more involved than your AngularJs implementation but should allow you to do what you want.

Angular documentation

https://angular.io/guide/router#resolve-pre-fetching-component-data

Video example from Angular University YouTube channel (no affiliation)

https://www.youtube.com/watch?v=6xmCNfPP90E

2
votes

If both the components belong to the same module, have you considered using a service instead? Add a model (or params) in the service, inject it as dependency in both the components, set its value in one component and retrieve in other components.

=== Update==

It possible using skipLocationChange option

customers.component.ts

this.router.navigateByUrl("/customers/details/1",{skipLocationChange:true});

and in details component, retrieve it like below

selectedCustId:string=""

    ngOnInit() {
    this.route.paramMap.subscribe((params:ParamMap)=>this.selectedCustId=params.get('id'))
      }
1
votes

As you said, the data key in every route may solve your case.

To summarize, Routes are like a huge tree and can be used as observable or as direct raw data thanks of the snapshot key.

To show you an example

MainComponent

ngOnInit() {
    this.route.data.subscribe((data: any )=> {
      data.test = 'wassup';

    })
  }

ChildComponent

ngOnInit() {
        this.route.parent.data.subscribe((data: any )=> {
            console.log(data);      
        })
/* or console.log(this.route.parent.snapshot.data) */
      }

SomewhereComponent

ngOnInit() {
        this.route.root.children[0].data.subscribe((data: any )=> {
            console.log(data);      
        })
      }

If you have a complex routes architecture I really recommend you to code a readerService that will go inside the tree from the root or from any place and would give you the whole map of params and all the wanted data.

1
votes

You have to import RouterModule and Routes from @angular/router.

    import { RouterModule, Routes } from '@angular/router';

    const routes: Routes = [{
      path: 'login/:stateToRedirect',
      component: LoginComponent,
      data: { 'yourParam': 'here goes your param' }
    }]

In your component for eg:

    import { ActivatedRoute, ParamMap } from '@angular/router';

    @Component({})...
    export class LoginComponent(){
       constructor(private route: ActivatedRoute){}
       private someFunction(){
          this.route.data.subscribe((data: any) => {
            console.log(data.yourParam);
          }); 
       }

You can pass static parameters like this without showing on the url