(In an Angular 2 app): If the data is already in memory, just return it, otherwise do a HTTP GET. It sounds like it should be simple. Is there any easier way than the following?
[LOGIC]
- If the data is not in memory and we haven't started the GET, start the GET, return an observable and also store the observable.
- If the data is not in memory, but we started the GET, return the stored observable.
- If the data is in memory, return a new observable which immediately returns the data.
[Update 1] Apparently this logic is not working. I see GET requests being sent every time getTopics is called! -- even though the http.get method only gets executed once. Each time a new caller gets a copy of the original observable, another GET request is sent!
[Update 2] I just learned that "nothing happens on an observable until you call subscribe". This explains why the GET requests are getting called when I return the observable. The callers then immediately call subscribe. This means that my logic is definitely wrong and I am likely back at square one in solving this "simple looking" problem.
[Update 3] Günter's solution includes the very important step of returning a "shared" observable. This solves the issue of sending multiple GET requests. The code below does NOT include this.
[CODE] (the data is an array of "topics")
@Injectable()
export class TopicsService {
private _topicsUrl = 'app/topics/topics.json';
private _topics: string[] = null;
private _topics$: Observable<string[]> = null;
constructor (private http: Http) {}
getTopics(): Observable<string[]> {
    // if topics are in memory, return them.
    if (this._topics != null) {
        return this.getTopicsTFromMem();
    // otherwise get them from the file.
    } else {
        return this.getTopicsFromFile();
    }
}
// return topics from memory. Actually return an observable which will return them.
getTopicsTFromMem(): Observable<string[]> {
    let topics$ = new Observable(observer => {
        observer.next(this._topics);
    });
    return topics$;
}
// return topics from file. Actually return an observable which will return them.
getTopicsFromFile(): Observable<string[]> {
    // If someone already started the http GET, then return existing observable.
    if (this._topics$ != null) {
        return this._topics$;
    }
    // otherwise start the GET
    let topics$ = this.http.get(this._topicsUrl)
        .map(this.extractData)
        .catch(this.handleError);
    topics$.subscribe(topics => {this._topics = topics;});
    this._topics$ = topics$;       
    return topics$;              
}
.....
 
    