Angular typically follows a classic pattern for data access that looks like this:
Traditional Data Access Pattern
getProducts(): Observable<Product[]> {
return this.http.get<Product[]>(this.productsUrl)
.pipe(
tap(data => console.log(JSON.stringify(data))),
catchError(this.handleError)
);
In the above code snippet, a method is used to return an Observable. When data is retrieved from the http endpoint, the Observable emits the data in a format specified by the Product[]
generic parameter, where Product
is an interface.
For a more reactive application design, developers often opt for a declarative/reactive approach. This involves changing the previous method into a property declaration, as demonstrated below:
Reactive Data Access Pattern
products$ = this.http.get<Product[]>(this.url)
.pipe(
tap(data => console.log(JSON.stringify(data))),
catchError(this.handleError)
);
It's worth noting that this new approach declares a property for the Observable rather than using a method. The convention of adding a $
suffix to products$
helps differentiate Observables from other types of data structures, such as objects or arrays.
The reactive data access pattern is commonly employed when dealing with interactive UI elements (such as filtering based on user selections), complex data operations (like merging data from multiple sources), and data sharing across different components (for cases where each component needs to react to changes in the shared data).
However, one challenge posed by the reactive data access pattern is how to pass parameters required by the URL when implementing this technique.
For instance, imagine a scenario where an http request necessitates specifying a category to fetch products only within that category:
this.http.get<Product[]>(`${this.url}?cat=${catId}`)
How can we include this category information since there are no methods involved?