Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular 2 route with parameters re-initializing component onInit

I have an issue where my component is re-initializing when I route to it with new parameters. Here are my routes.

const appRoutes: Routes = [
  { path: '', component: MyNewComponentComponent },
  { path: 'tiles', component: DisplayTileData },
  { path: 'tiles/:master/:filters', component: DisplayTileData } 
];

I route to "tiles" and do a service call to fetch some data. I then have a couple of buttons that route back to the same component with values for "master" and "filters". Routing back to the component with parameters re-initializes the component and repeats the service call. I also have a text input on the page. When I first route to this component and add text, the route with parameters is also wiping out that text.

<a *ngFor="let tile of tiles">{{tile.id}}</a><br/><br/>

<input class="form-control" maxlength="30" minlength="3" name="from" ng-reflect-maxlength="30">
<button (click)="addNumberToFilter(15)"></button>
<button (click)="addNewMasterPath('do')">add new Number to Filter</button>

Is there a way to prevent this route re-initialization when routing with new parameters.

I have defaults values for the buttons. Here are the methods.

public variable: any = [3,4];
public master: any = 'eat';

addNewMasterPath(newMasterVariable) {
    this.master = this.master + '-' + newMasterVariable;
    var newMap = this.variable.map(items => { return items}).join('-');
    this.router.navigate(['tiles/', this.master, newMap]);
}

addNumberToFilter(newParameter) {
    this.variable.push(newParameter);
    var newMap = this.variable.map(items => { return items}).join('-');
    this.router.navigate(['tiles/', this.master, newMap]);
}
like image 517
David Aguirre Avatar asked Jan 16 '17 22:01

David Aguirre


1 Answers

Routing back to the component with parameters re-initializes the component and repeats the service call.

That is because the new route where you go is specified as a different route in your application. For the component not to be reinitialized, it has to be the same route.

I see different possibilities here, depending on your specific scenario:

If you only load /tiles to make a service call and then route to tiles/:master/:filters, but /tiles component doesn't make sense without receiving this data, you could consider using a resolver to make the API call, and then having only tiles/:master/:filters route.

From the official docs, you can do the service call inside the resolver:

@Injectable()
export class MasterFiltersResolver implements Resolve<MasterFilter> {
  constructor(private cs: MasterFiltersService, private router: Router) {}
  resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Promise<Crisis> {
    let id = route.params['id'];
    return this.cs.getData(id).then(data => {
      if (data) {
        return data;
      }
    });
  }
}

Then in your route you can specify it as:

{ path: '', component: MyNewComponentComponent },
{ path: 'tiles/:master/:filters', component: DisplayTileData, 
    resolve: {
        masterFilters: MasterFilterResolver
    } 
} 

This way, it will retrieve the data you need before loading your component.

If your /tiles route component makes sense as a standalone component without master and filters data:

In this case, you can use optional parameters.

When having optional parameters, you would have only this route on your route definition

{ path: '', component: MyNewComponentComponent },
{ path: 'tiles', component: DisplayTileData }

And then navigating to this route through router.navigate('/tiles', {master: '', filter: ''}.

In this case, your component will need something like:

constructor(private route: ActivatedRoute) {}

this.route.params.subscribe(params => {
  // do something
});

this.route.params is an observable of params, so you can be reactive to any change to do async operations.

like image 137
Bertofer Avatar answered Oct 03 '22 08:10

Bertofer