Angular Patterns
I began to work heavily with VueJS back in 2018 when I worked as a Trainee Developer in Grupo.Unico, and after that I went to React and never stopped. React is amazing but it's complicated to deal with. For instance, it's hard to achieve an observable pattern in React because of the overcomplicated Redux library. With VueJS for instance we can easily achieve an observable pattern by using VueX but until today, I've never really understood Angular, never have done even a ng new hello-world --minimal much because the frontend stack of the companies that I had opportunity to work never included Angular and it is well known that Angular embraced the cathedratical Java developers but, believe it or not Angular has simple and interesting patterns, batteries included and has a nice modular structure of components.
Pipes
Are classes in Angular that have the objective to transform and display an entry data into a format specified in the code where the pipe is called. Angular already has built-in pipes for common transformation such as strings, currency amounts, dates, and other data and this speeds-up the development process, for instance, you don't really need to write a format function that formats date into your locale rules, this pipe is already built. Let's understand how they work in the example bellow:
<p>The hero's birthday is {{ birthday | date }}</p>
The component's birthday
value flows through the pipe operator, |
to the date
function.
Parameters
It's also possible to pass parameters into some pipes, for instance you can pass which locale rule to format the birth as in the exemple above, which leads to:
<p>Hawkmoon's birthday is {{ birthday | date:"dd/MM/yy" }}</p>
Chained Pipes
This is a very nice behavior of the pipes, you can chain a pipe output into another pipe to fine-tune the transformation needed to be displayed in the front, for instance you can transform an entry data into a date and then put it to uppercase, as in the example below:
<p>Elric's birthday is {{ birthday | date:"dd/MM/yy" | uppercase }}
You can also write your own custom pipes! It's amazing and very easy to use, something that I miss in the other frameworks.
Observables
Angular uses the ReactiveX API, specifically RxJS, to implement the reactive programming paradigm. It provides the Observable type, that we use to define as the return type of an asynchronous function call, much like we do with promises, the difference is that we also have the Operators that are a series of functions to process data when the result is fulfilled.
For instance, let's fetch some data from an API service and make it an Observable:
getData(): Observable<Data>{
return this.http.get<Data>(this.url);
}
In the code the getData runs asynchronously and has a return type as an Observable that will look for the Data type. We should use an operator to subscribe to an observable making the function an observer:
fetchBackendData(): void {
this.getData().subscribe((e) => {
console.log(e)
});
}
We've defined the function fetchBackendData that will be the observer of an Observable, the subscribe operator is used to connect one to another, kinda like the promise function then with the difference that an Observable works with an stream of data while a promise return just a single value that may be available in the future.
Another difference is that the subscribe function may accept up to three callback functions, that are:
-
onNext: An Observable calls this method whenever the Observable emits an item. This method takes as a parameter the item emitted by the Observable.
-
onError: An Observable calls this method to indicate that it has failed to generate the expected data or has encountered some other error. This stops the Observable and it will not make further calls to
onNext
oronCompleted
. TheonError
method takes as its parameter an indication of what caused the error (sometimes an object like an Exception or Throwable, other times a simple string, depending on the implementation). -
onCompleted: An Observable calls this method after it has called
onNext
for the final time, if it has not encountered any errors.
Operators
We just saw the subscriber operator but, as we do in Pipes We can also perform chained operations, it's possible to use operators to create observables from observables, to transform them, to filter results and so forth. Let's transform data from the observable before we subscribe to it:
fetchBackendData(): void {
this.getData().map(value => JSON.stringify(value)).subscribe((e) => {
console.log(e)
});
}
A complete list of operators can be found at the [ReactiveX docs](ReactiveX - OperatorsReactiveX - Operators).
Single
It's a variant of an Observable that always emits one value or an error notification and instead of subscribing to it with three methods, you use just the following:
-
onSucess: a Single passes this method the sole item that the Single emits
-
onError: a Single passes this method the Throwable that caused the Single to be unable to emit an item
A Single will call only one of these methods, and will only call it once. Upon calling either method, the Single terminates and the subscription to it ends.
Subject
A subject it's an observable that observes, and it can subscribe to many other Observables, it also can pass through items observed, reemitting them and it can add new values to the stream of data by using the next method.
An Observer can subscribe to the Subject and receive value from it. Subject adds them to its collection observers. Whenever there is a value in the stream it notifies all of its Observers.
We can define A subject with the following code, using the next
method to emit the value to its subscribers:
export class AppComponent {
subject$ = new Subject();
ngOnInit() {
this.subject$.subscribe(val => {
console.log(val);
});
this.subject$.next("1");
this.subject$.next("2");
this.subject$.complete();
}
}
Notice that we use the $ suffix (popularized by Cycle.js) to [indicate that the variable is an Observable](Angular - The RxJS library) and since a Subject is also a Observable we use it on the variable that will hold the Subject instance.
There's a lot more to it but, I think that it makes sense that Angular chooses to use ReactiveX instead of trying to write something new, trying to reinvent the wheel.
References
- https://www.tektutorialshub.com/angular-tutorial/
- https://www.cod3r.com.br/courses/angular-9-essencial
October 12, 2023