samteb
samteb

Reputation: 63

Is it a good practice to use a route resolver to pass static data to a route component in Angular 8?

We have a User component that receives a user object as an @input:

export class UserComponent implements OnInit {
  @Input() user: User;

  constructor() {}
}

Here the corresponding template:

<div class="user-box">
  <img class="avatar" [src]="user.avatar" alt="user_picture">
  <div class="infos">
    <div class="username">{{ user.username }}</div>
    <div>{{ user.email }}</div>
    <div class="gender">{{ user.gender }}</div>
  </div>
</div>

In a route component UsersList (primary <router-outlet>) we need to display a list of users to the screen:

<user
  *ngFor="let user of users
  [user]="user"
  (click)="selectUser(user)">
</user>

Then, when we click to select a user from the list, we show the selected user data using the same User component but this time as a route component (named <router-outlet name="selected">):

Application Mockup

Here our routes:

const ROUTES: Routes = [
  {
    path: '',
    component: UsersList
  },
  {
    path: ':username',
    component: UserComponent,
    outlet: 'selected'
  }
];

So, here the selectUser() function:

selectUser(user: User) {
  return this.router.navigate([ { outlets: { selected: [ user.username ] } } ], { state: { user } });
}

And inside our User component, we need to implement the OnInit interface:

if (this.route.outlet === 'selected') {
  this.route.paramMap.pipe(map(() => window.history.state)).subscribe(state => {
    if (!state.user) {
      return this.router.navigate([ { outlets: { selected: null } } ]);
    }
    this.user = state.user;
  });
}

All of this works perfectly fine! What I am wondering though is if it's a good practice to do it this way?

FYI, I have also tried to use a route resolver but I can't have access to the NavigationExtras state object... The only way to get the user data inside a resolver is to pass it as queryParams. It can be fine when we have 3 properties, but, if we have 10+ properties, the URL becomes ugly and messy. And also, it seems that a resolver role is to resolve asynchronous data and not passing static data.

Thanks for giving your insights!

Upvotes: 1

Views: 2658

Answers (1)

michelepatrassi
michelepatrassi

Reputation: 2086

The good practice, or let's say "the Angular way", is to use route resolvers how is written in the documentation: https://angular.io/guide/router#fetch-data-before-navigating.

I use resolvers when I can, so I can write clean page components that get the data they need from the router as they are instantiated (I can also re-use the resolver for other routes, but that rarely happens).

This makes also the routes independent from each other: I can see the user page before going into the user list page, I don't think I can do that with your current code. Plus, if the user does not exist, I could redirect to the 404 page from the resolver directly.

By the way, resolvers could have some drawbacks to keep in mind:

  • if you work with real-time async data, you lose the real-time update because the document if fetched just once (usually by take(1)) and the stream gets closed
  • if you're using something like Ionic, which caches pages, you could have issue with outdated data

Upvotes: 1

Related Questions