Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Want to prevent Component recreation while routing in Angular 2

Let's say we have two routes Dashboard and Profile. Dashboard has dynamic tabs feature like Google spreadsheet. I want to do some interactions(build charts, visualizing some data) creating tabs in the Dashboard. Now, if I route to Profile and then route back to Dashboard, I want to see what was before in those tabs in Dashboard. It means, I want to maintain the state in the client side. AFAIK while routing between components, it recreates components. Is it possible to make spreadsheet like application while using angular 2 routing? I need to use routing because in my application I have to use LazyLoading feature.

So what should be the idea? I am new to angular 2.

like image 320
pd farhad Avatar asked Sep 29 '16 05:09

pd farhad


People also ask

What are route guards in Angular 2?

Angular's route guards are interfaces which can tell the router whether or not it should allow navigation to a requested route. They make this decision by looking for a true or false return value from a class which implements the given guard interface.

What is the purpose of wildcard route in Angular?

Setting up wildcard routeslink To add this functionality to your application, you set up a wildcard route. The Angular router selects this route any time the requested URL doesn't match any router paths. To set up a wildcard route, add the following code to your routes definition.


2 Answers

Currently components are reused only when only route parameters change while staying on the same route.

If the route is changed, event when the new route adds the same component, the component is recreated.

The preferred workaround is to keep the model in a shared service that stays alive during route changes and use the data from this service to restore the previous state of the component.

It was mentioned that there are plans to support custom reuse strategies with the router but no timeline when this will become available.

Update

Support for custom reuse strategy was added to Angular2.

See also

  • https://www.softwarearchitekt.at/post/2016/12/02/sticky-routes-in-angular-2-3-with-routereusestrategy.aspx
  • https://github.com/angular/angular/issues/7757#issuecomment-236737846

  • Angular2 router 2.0.0 not reloading components when same url loaded with different parameters?

like image 197
Günter Zöchbauer Avatar answered Sep 19 '22 05:09

Günter Zöchbauer


Thanks to the example provided by @Günter Zöchbauer, for my own understanding I decided to distill a minimal example.

See it in action

In Summary:

First I implemented a RouteReuseStrategy:

export class CustomReuseStrategy implements RouteReuseStrategy {

    handlers: {[key: string]: DetachedRouteHandle} = {};

    calcKey(route: ActivatedRouteSnapshot) {
        let next = route;
        let url = '';
        while(next) {
            if (next.url) {
                url = next.url.join('/');
            }
            next = next.firstChild;
        }
        return url;
    }

    shouldDetach(route: ActivatedRouteSnapshot): boolean {
        return true;
    }

    store(route: ActivatedRouteSnapshot, handle: DetachedRouteHandle): void {
        this.handlers[this.calcKey(route)] = handle;
    }

    shouldAttach(route: ActivatedRouteSnapshot): boolean {
        return !!route.routeConfig && !!this.handlers[this.calcKey(route)];
    }

    retrieve(route: ActivatedRouteSnapshot): DetachedRouteHandle {
        if (!route.routeConfig) { return null; }
        return this.handlers[this.calcKey(route)];
    }

    shouldReuseRoute(future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot): boolean {
        return this.calcKey(curr) === this.calcKey(future);
    }
}

Within my AppModule, I added a new provider and configured some routes:

export const ROUTES: Routes = [
  {
    path: 'one',
    component: OneComponent
  },
  {
    path: 'two',
    component: TwoComponent
  },
];

@NgModule({
  ...
  imports: [... RouterModule.forRoot(ROUTES)...]
  providers: [...{ provide: RouteReuseStrategy, useClass: CustomReuseStrategy }...],
  ...
})
export class AppModule { }

Finally, I defined some components as follows:

@Component({
  selector: 'my-app',
  template: `
    <a [routerLink]="['/one']" >Route One</a><br>
    <a [routerLink]="['/two']" >Route Two</a><br>
    <router-outlet></router-outlet>
  `
})
export class AppComponent  {}

@Component({
  selector: 'app-one',
  template: `
  Route One currently showing<br>
  <input type="text" placeholder="enter some text">
  `,
})
export class OneComponent {}

@Component({
  selector: 'app-two',
  template: `
  Route Two currently showing<br>
  <input type="text" placeholder="enter some text">
  `,
})
export class TwoComponent {}
like image 26
Stephen Paul Avatar answered Sep 19 '22 05:09

Stephen Paul