By leveraging the RxJS library for data collection, we can quickly develop a reactive application. Let’s look at a common implementation for processing data in an angular application. Then we will modify this approach to demonstrate how to leverage the RxJS library.
There are multiple libraries available that help developers quickly add reactive programming patterns to their application code.
For this demonstration, I have set up a basic ASP.NET Core Angular Web Application using Visual Studio 2019, .NET Core 3.1, and Angular 11. I also used EF Core PowerTools to reverse engineer the Northwind SQL Server database to use for sample data.
We will be implementing a simple application where a user can select a supplier to view their contact information. The code snippet below represents the API endpoint I created to retrieve the supplier data from the Northwind sample database.
The following is a familiar pattern developers use to collect data in the frontend of an application. To implement it, we must first set up a service with a method that makes a call to the API endpoint we created.
We can see here that the supplier service has a getSuppliers method. This method makes a call to the API endpoint and returns an observable. Any http method returns an observable of some type. In our service, the get request is returning an observable of supplier arrays. An observable from an http request will only emit a value once after the request is complete. So, when the observable receives a response, it will emit the data that we requested, which we can then use in the component class.
The supplier component class implements the onInit angular lifecycle hook. The call to the getSuppliers service method is made inside this hook, which is fired off after the application has initialized any data-bound properties. We subscribe to the method to listen for the incoming data. The collected supplier data is then bound to the supplierInformation variable. Once the data is bound to the property, we can then display or utilize it however needed. In this case, we will create a list of the suppliers that the user can select from to display the supplier’s contact information.
In the supplier html file, we are using the ngFor structural directive to loop through the supplier property that we bound the data to. This will create a list of all the supplier names, and then when a user selects one of them, their contact information will be dynamically displayed.
This method of obtaining data on the application frontend gets the job done. However, there is another solution that will provide some additional development advantages. Let’s update our data retrieval method to create a stronger reactive implementation. First, we must modify our supplier service.
Here you can see that rather than creating a method to make the API call, we assign the http get request to an observable. In this case, we are allocating the http get request to the suppliers$ observable, which we can then go ahead and use in our component class.
In the component class, we no longer need to utilize the ngOnInit lifecycle hook. Instead, we create a local property and set it equal to the observable from our service. This declarative approach to retrieving the data is one step towards integrating reactive programming into our application. This implementation removes the need to hook into the components control flow. This allows us to focus primarily on what the program must accomplish rather than worrying about when each step must take place. Now, we can go ahead and use this observable to display the data in our template.
Here you can see we are using the async pipe. The async pipe allows us to bind and subscribe to the suppliers$ observable to check for changes. When a new value is emitted, the pipe will retrieve the data and then populate the specified variable, suppliers, with the data. We can then use the ngFor directive to loop through and display the information.
Both of these approaches to collecting data for use on the application frontend produce the same results. However, the second implementation is set up to provide the application with additional development and performance opportunities. Some of these added benefits include improving change detection and the ability to merge streams together.
In angular, the default approach for change detection is to run a detection cycle anytime an event occurs in a component. When an application begins to grow and views become more complex, running change detection cycles for every event or change occurrence can have a significant impact on performance. In our second data collecting implementation, we bound directly to an observable. This will allow us to utilize the OnPush change detection strategy rather than the default. The OnPush strategy checks for changes for three different scenarios: when a component input property changes, when an event emits, or in the case of our solution, when a bound observable emits a value. Since we bound to an observable, we can utilize the OnPush change detection and reduce the number of detection cycles.
Our optimized data retrial solution also gives us the ability to merge streams using the RxJS combineLatest method. Merging observables together combines multiple streams into a new stream. The newly composed stream will use the latest emitted value for each of its inputs. A scenario where this would be useful is when separate data entities need to be used for the same functionality. For example, let’s say that in our sample application we want to display both the contact information and the details for products offered by the selected supplier. We would create another API endpoint to retrieve the product details. Then in our service, we would create a products observable and set it equal to the http get request. We would then pass both streams to combineLatest which will emit an array of values, one for each input stream. This creates a new stream that contains both the supplier contact information and the supplier product information. To display the data, we would then only need to update our component to use the merged stream in place of the supplier stream. Merging streams allows us to put together and construct the information needed in our view.
RxJS is a very powerful library, and when leveraged to its full potential, it opens up numerous development benefits. There are many great resources that show how to leverage the various library operators to build improved and responsive solutions. Utilizing these reactive programming features will drive optimized applications and provide for an overall better user experience.
From developing simple single page to complex web-based internet applications, Tallan uses cutting edge technology to create custom sites that increase user engagement for your business. Click here to learn more.