Keeping State On A Page When Clicking Away and Coming Back

I have 2 forms that I am working with on my application.

1 - customer view. This is the view that a user will use when looking at a customer’s details. They can get to this from the Search page.

2 - Search View. This is the form that allows a user to search for an invoice or customer, and get the results and then click on that for a specific customer.

Problem:

I need to be able to have the user click on a customer, and then go back to the Search view to see the results again without running the search again.

Right now, I am having trouble thinking of how this can be done, but I am sure it can be done.

Is there a way to store, say, the search obj and results after clicking away from it, and then re-fill the page when it’s clicked on?

1 Like

The most simple way would be to have a Service which you inject in your search comp. The search term and result would be stored in the service and once you come back in the bind lifecycle (or activate if via Router) you check whether a search term and result is in the service and reapply it. Alternatively you can also directly bind to your services data properties.

The service is just a simple vanilla class. Due to the default DI behaviour it will be resolved as Singleton as opposed to your components which get rebuilt If navigated via the Router by default

1 Like

I am trying to look up how to use a Service in Aurelia, but coming up blank. Do you have any links that I can read to get more information?

My other idea was to have the search object be passed along to customer, and then when the user clicks on Search again, send that along with, so that it can fill out the form and results.

1 Like

A service is essentially any class (that is not a component) that you export and then import into another file. Something like this:

// SearchService.ts
import {HttpClient} from "aurelia-http-client";

export class SearchService {
    searchResults: any[] = []; // usually have a better type than any

    constructor(private http: HttpClient) { }

    async doSearch(parameters): Promise<any> {
        const response = await this.http.get("my search url");

        // Store the search results on the class
        this.searchResults = response.content;
        return this.searchResults;
    }
}

// search-page.ts

import { autoinject, inlineView } from "aurelia-framework";
import { SearchService } from "./SearchService";

@inlineView(`<template> your template goes here</template>`)
@autoinject
export class SearchPage {
    searchResults: any[] = [];
    searchParamaters: any;

    // inject the SearchService. With Aurelia DI defaults, this will be a singleton
    constructor(private searchService: SearchService) { }

    // As SearchService is a singleton, if you have previously searched, the results will be available
    async bind() {
        if (this.searchService.searchResults.length >= 0) {
            this.searchResults = this.searchService.searchResults;
        } else {
            this.searchResults = await this.searchService.doSearch(this.searchParameters);
        }
    }
}
2 Likes

You could just add a query into the current url

1 Like

I’m not sure if there are downfalls to this approach but you can just decorate your view-model with the @singleton decorator and it 'll hold its state between navigation. It achieves the same thing as injecting a singleton service. I’ve done this in my projects and it usually achieves what I’m after.

The approaches listed above are pretty clean though and achieve the same outcome.

1 Like

you’ll run into problem if you need to use the same component multiple times in the app.
or if you are injecting the “host” element to your VM. (because it’ll be done only the first time - and then - if for some reason things changes - it will not be synchronized).

other from that, I don’t see what could go wrong by having the component as a singleton.
(other than the obvious reason of separation of concerns - that kind of state belong in a service).

2 Likes