3

I have a resolver on one of my routes in order to allow it to get data before the page actually loads. This required multiple requests therefore I am using rxjs function forkJoin. This returns the data great and the page doesn't load until all of the data is fully loaded, which is exactly how I want.

However, the data that is gets is pretty hefty meaning it can take a while before the route loads. I want to somehow, still resolve this route but then cache it and let the component know that this is cached.

I rely on the data coming back from the activatedRoute within the component as the page needs this. So I need it to stop overriding what is currently there as well.

This is my code so far:

Resolver:

const postId: string = this.postService.data.post.id;

const authorData$: Observable<HttpResponse<any>> = this.authorService.getAuthor();
const commentsData$: Observable<HttpResponse<any>> = this.commentsService.getComments();

I understand that this can be done in one request but this is just an example of what I would be using it for. So I don't want a suggestion that says put it in one request.

this.activatedRoute.data.subscribe((data) => {
   this.author = data[0][0];
   this.comments = data[0][1].data;
});

So I want to do this only on the first load of the component.

Thanks in advance.

5
  • 1
    I see two options: cache at HttpClient level through an interceptor + cache service (see angular.io/guide/http#caching) or or create a specialized statefull service that tracks the last parameters used for the requests + the request responses. Whenever the resolver tries to fetch, the logic should check the service and confirm if the new parameters match the previously store ones, in which case the cached responses can be used. Commented Jul 23, 2018 at 18:01
  • I never thought about that last option. What would be the best one do you personally think? Commented Jul 23, 2018 at 18:03
  • However, I don't think the second option would work as there would be no way to store the first one that it has got in order to check against the current one? Commented Jul 23, 2018 at 18:05
  • 2nd, http caching is mostly used to replay a response during the processing of a new request. Not to avoid new requests. Commented Jul 23, 2018 at 18:06
  • Cache it with a ReplaySubject Commented Jul 23, 2018 at 18:34

1 Answer 1

10

One way of doing this is to introduce a replay subject in the resolver which will act as a cache. The resolver will always return this subject, but it will only request data, if it has not requested any data yet.

I made a simple example where the resolver only has to return a number, which it gets from a simple data service.

class Resolver implements Resolve<number> {
    // We need to keep track on if a request has already been sent
    requested = false;
    // The replay subject will emit the last value that has been passed in
    subject = new ReplaySubject<number>(1);

    resolve(route: ActivatedRouteSnapshot): Observable {
        // Request data only if it has not been requested yet
        if (!this.requested) {
            this.requested = true;
            
            // Do your heavy call here
            this.service.getData()
                // Emit your data into the subject
                .subscribe(nr => this.subject.next(nr));
        }

        // Return the subject. Pipe in first() because resolvers 
        // only emit on completion of an observable.
        return this.subject.pipe(first());
    }

}

You should be able to do the same. If you have multiple calls you can either use forkJoin or similar to execute both calls and supply the result to the replay subject. Or you could create two separate resolvers, which are only responsible for one result object each.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.