Updated with code to clarify. The TVC Component hosts a Trading View lightweight-charts component.
There is a side nav with a list of items. And every time a new/different item is selected, it fires this.data.getDataForSymbol() in the Main Content Component. The chart re-renders perfectly when NOT using the caching... but when the cache is used (and confirmed to be working)... the graph does not re-render.
Here is the component that renders the chart:
@Component({
selector: 'tvc',
template: '<div #chart></div>',
})
export class TvcComponent implements AfterViewInit {
@ViewChild('chart') chartElem: ElementRef;
@Input()
data: (BarData | WhitespaceData)[] | null;
chart: IChartApi = null;
ngAfterViewInit() {
this.buildChart();
}
buildChart() {
this.chart = createChart(<HTMLElement>this.chartElem.nativeElement, {
width: 600,
height: 300,
crosshair: {
mode: CrosshairMode.Normal,
},
});
this.chart.timeScale().fitContent();
const candleSeries = this.chart.addCandlestickSeries();
candleSeries.setData(this.data);
}
}
And here is the component that hosts the TvcComponent, providing data to the chart:
@Component({
selector: 'main-content',
template: `
<div *ngIf="monthly$ | async as monthly">
<tvc
[data]="monthly"
></tvc>
</div>`
})
export class MainContentComponent implements OnInit {
monthly$: Observable<any[]>;
constructor(
private route: ActivatedRoute,
private itemStore: ItemStore,
private data: DataService
) {}
ngOnInit(): void {
this.route.params.subscribe((params) => {
let id = params['id'];
this.itemStore.items$.subscribe((items) => {
this.monthly$ = this.data.getDataForSymbol(id, 'monthly');
});
});
}
}
Here is the relevant code for the interceptor service:
@Injectable({ providedIn: 'root' })
export class CacheInterceptor implements HttpInterceptor {
constructor(private cache: HttpCacheService) {}
intercept(
req: HttpRequest<any>,
next: HttpHandler
): Observable<HttpEvent<any>> {
const cachedResponse = this.cache.get(req.urlWithParams);
if (cachedResponse) {
console.log(`${req.urlWithParams}: cached response`);
return of(cachedResponse);
}
return next.handle(req).pipe(
tap((event) => {
if (event instanceof HttpResponse) {
this.cache.put(req.urlWithParams, event);
console.log(`${req.urlWithParams}: response from server`);
}
})
);
}
}
and the caching service:
@Injectable()
export class HttpCacheService {
private cache = {};
get(url: string): HttpResponse<any> {
return this.cache[url];
}
put(url: string, resp: HttpResponse<any>): void {
this.cache[url] = resp;
}
}
I've implemented an HttpInterceptor for caching (example from Angular Github), and am caching the HttpResponse for data that is then subscribed to with an async pipe in the template - and passed as an input property to a child component. The observable contains data that renders a chart.
The data is (largely) static and selecting different items triggers a new Http Request. So if someone bounces back-and-forth between several charts, they will be making multiple (repeat) calls unnecessarily. Hence, the caching.
The problem is that while the cache works beautifully as determined via console logging)... the graph does not update/re-render when accessing data from the cache. The first time you select Item A, it gets the data from the server and renders correctly. If you move select Item B (not in cache), it makes the server request, puts the response in the cache, and renders the correct graph. The problem is if you switch BACK to Item A, it gets the correct data from the cache, but does NOT update the graph.
I am using default Change Detection.