fracz
fracz

Reputation: 21249

How to reuse data between routes in Aurelia?

I have an user entity in the system and the following route fetches it from server and displays its details:

routerConfiguration.map([
  // ...
  {route: 'user/:id', name: 'user-details', moduleId: './user-details'}
]);

Now I want to display an edit form for the displayed user. I have the following requirements:

  1. Edit form should have a separate URL address, so it can be sent to others easily.
  2. When user clicks the Edit button on the user's details page, the edit form should use an already loaded instance of the user (i.e. it should not contact the API again for user details).
  3. When user clicks the Edit button on the user's details page and then the Back button in the browser, he should see the details page without edit form again.

1st attempt

I tried to define the edit form as a separate page:

routerConfiguration.map([
  // ...
  {route: 'user/:id/edit', name: 'user-edit', moduleId: './user-edit'}
]);

This passes the #1 and #3 requirement but it has to load the user again when the edit form is opened.

I don't know any way to smuggle some custom data between the routes. It would be perfect if I could pass the preloaded user instance to the edit route and the edit component would use it or load a new one if it is not given (e.g. user accesses the URL directly). I have only found how to pass strings to the routes in a slighlty hacky way.

2nd attempt

I decided to display the edit form in a modal and show it automatically when there is a ?action=edit GET parameter. The code inspired by this and this question:

export class UserDetails {
  // constructor
  activate(params, routeConfig) {
    this.user = /* fetch user */;
    this.editModalVisible = params.action == 'edit';
  }
}

and when the user clicks the Edit button, the following code is executed:

displayEditForm() {
  this.router.navigateToRoute('user/details', {id: this.user.id, action: 'edit'});
  this.editModalVisible = true;
}

This passes #1 (the edit url is user/123?action=edit) and #2 (the user instance is loaded only once). However, when user clicks the Back browser button, the URL changes as desired from user/123?action=edit to user/123 but I have no idea how to detect it and hide the edit form (the activate method is not called again). Therefore, this solution fails the #3 requirement.

EDIT:

In fact, I have found that I can detect the URL change and hide the edit form with event aggregator:

ea.subscribe("router:navigation:success", 
  (event) => this.editModalVisible = event.instruction.queryParams.action == 'edit');

But still, I want to know if there is a better way to achieve this.

The question is

How to cope with this situation in a clean and intuitive way?

Upvotes: 5

Views: 472

Answers (1)

Jeff G
Jeff G

Reputation: 2175

How about adding a User class that will serve as the model and use dependency injection to use it in your view-models?

export class User {
    currentUserId = 0;
    userData = null;

    retrieve(userId) {
        if (userId !== this.currentUserId) {
            retrieve the user data from the server;
            place it into this.userData;

        }

        return this.userData;
    }
}

Upvotes: 3

Related Questions