Reader small image

You're reading from  Angular for Enterprise Applications - Third Edition

Product typeBook
Published inJan 2024
Reading LevelExpert
PublisherPackt
ISBN-139781805127123
Edition3rd Edition
Languages
Right arrow
Author (1)
Doguhan Uluca
Doguhan Uluca
author image
Doguhan Uluca

Doguhan Uluca is a Principal Fellow at Excella in Washington, D.C., where he leads strategic initiatives and delivers critical systems. He has technical expertise in usability, mobility, performance, scalability, cybersecurity, and architecture. He is the author of the Angular for Enterprise Application Development books, has spoken at over 30 conferences, and is an Angular GDE Alumni. Doguhan has delivered solutions for Silicon Valley startups, Fortune 50 companies, and the U.S. Federal Government, and he is passionate about contributing to open-source projects and teaching.
Read more about Doguhan Uluca

Right arrow

Recipes – Master/Detail, Data Tables, and NgRx

In this chapter, we complete the router-first architecture implementation on LemonMart by implementing the top three most used features in business applications: master/detail views, data tables, and state management. I will demonstrate data tables with server-side pagination, highlighting the integration between the frontend and backend using LemonMart and LemonMart Server.

We will leverage the router orchestration concept to orchestrate how our components load data or render. We will then use resolve guards to reduce boilerplate code when loading data before navigating to a component. We will use auxiliary routes to lay out components through the router configuration and reuse the same component in multiple contexts.

We will then dive into NgRx using the LocalCast Weather app and explore NgRx Signal Store with LemonMart, so you can become familiar with more advanced application architecture concepts in Angular. By the...

Technical requirements

The most up-to-date versions of the sample code for the book are on GitHub at the repository linked in the following list. The repository contains the final and completed state of the code. You can verify your progress at the end of this chapter by looking for the end-of-chapter snapshot of code under the projects folder.

For Chapter 9:

Be sure that lemon-mart-server is up and running. Refer to Chapter 7, Working with REST and GraphQL APIs.

  1. Clone the repositories at https://github.com/duluca/local-weather-app and https://github.com/duluca/lemon-mart.
  2. Execute npm install on the root folder to install dependencies.
  3. The beginning state of the project is reflected at:
    projects/stage11
    
  4. The end state of the project is reflected at:
    projects/stage12
    
  5. Add the stage name to any ng command to act only on that stage:
    npx ng build stage12
    

Note that the dist...

Loading data with resolve guard

A resolve guard is a different kind of router guard, as mentioned in Chapter 6, Implementing Role-Based Navigation. A resolve guard can load necessary data for a component by reading record IDs from route parameters, asynchronously loading the data, and having it ready when the component activates and initializes.

The major advantages of a resolve guard include reusability of the loading logic, a reduction of boilerplate code, and the shedding of dependencies because the component can receive the data it needs without having to import any service:

  1. Create a new user.resolve.ts class under user/user:
    src/app/user/user/user.resolve.ts
    import { inject } from '@angular/core'
    import { ActivatedRouteSnapshot, ResolveFn } from '@angular/router'
    import { catchError, map } from 'rxjs/operators'
    import { transformError } from '../../common/common'
    import { User } from './user'
    import { UserService...

Reusing components with binding and route data

Now, let’s refactor the viewUser component so that we can reuse it in multiple contexts. User information is displayed in two places in the app per the mock-ups created.

The first place is the Review step of the user profile that we implemented in the previous chapter. The second place is on the user management screen on the /manager/users route, as follows:

A screenshot of a computer  Description automatically generated

Figure 9.1: Manager user management mock-up

To maximize code reuse, we must ensure that our shared ViewUser component can be used in both contexts.

In the first use case, we bind the current user to the Review step of the multi-step input form. In the second use case, the component will need to load its data using a resolve guard, so we don’t need to implement additional logic to achieve our goal:

  1. Update the viewUser component to inject the Router and ActivatedRoute. In ngOnInit we need to set currentUser from the route in and subscribe...

Master/detail view using auxiliary routes

The true power of router-first architecture comes to fruition with auxiliary routes, where we can influence the layout of components solely through router configuration, allowing for rich scenarios where we can remix the existing components into different layouts. Auxiliary routes are routes that are independent of each other where they can render content in named outlets that have been defined in the markup, such as <router-outlet name="master"> or <router-outlet name="detail">. Furthermore, auxiliary routes can have their parameters, browser history, children, and nested auxiliaries.

In the following example, we will implement a basic master/detail view using auxiliary routes:

  1. Implement a simple component with two named outlets defined:
    src/app/manager/user-management/user-management.component.ts
      template: `
        <div class="h-pad">
          <router-outlet name="...

Data tables with pagination

We have created the scaffolding to lay out our master/detail view. In the master outlet, we will have a paginated data table of users, so let’s implement UserTableComponent, which will contain a MatTableDataSource property named dataSource. We will need to be able to fetch user data in bulk using standard pagination controls such as pageSize and pagesToSkip and narrow down the selection further with user-provided search text.

Let’s start by adding the necessary functionality to UserService:

  1. Implement a new IUsers interface to describe the data structure of the paginated data:
    src/app/user/user/user.service.ts
    ...
    export interface IUsers {
      data: IUser[]
      total: number
    }
    
  2. Update the interface for UserService with a getUsers function:
    src/app/user/user/user.service.ts
    ...
    export interface IUserService {
      getUser(id: string): Observable<IUser>
      updateUser(id: string, user: IUser): Observable...

NgRx store and effects

As covered in Chapter 1, Angular’s Architecture and Concepts, the NgRx library brings reactive state management to Angular based on RxJS. State management with NgRx allows developers to write atomic, self-contained, and composable pieces of code, creating actions, reducers, and selectors. This kind of reactive programming isolates side effects in state changes. NgRx is an abstraction layer over RxJS to fit the Flux pattern.

There are four major elements of NgRx:

  • Store: The central location where state information is persisted. You implement a reducer to store a state transition in the store and a selector to read data out of the store. These are atomic and composable pieces of code.

    A view (or user interface) displays data from the store by using a selector.

  • Action: Unique events that happen throughout your app.

    Actions are triggered from a view with the purpose of dispatching them to the store...

NgRx ecosystem

Now that you understand NgRx better beyond just theory, let’s examine the different available options within the ecosystem.

Here are some popular options from the community, including sibling packages from NgRx:

  • NgRx/Data, a gentle introduction to NgRx with simplified entity management
  • NgRx/ComponentStore, a component-scoped version of NgRx/Store with less boilerplate
  • NgRx/SignalStore, the next generation of state management in Angular
  • Akita, a reactive state management offering tailor-made for JS applications
  • Elf, a reactive store with magical powers

Let’s explore these options.

NgRx/Data

If NgRx is a configuration-based framework, NgRx Data is a convention-based sibling of NgRx. NgRx Data automates the creation of stores, effects, actions, reducers, dispatches, and selectors. If most of your application actions are CRUD (Create, Retrieve, Update, and Delete) operations, then NgRx Data can achieve...

Configuring server proxies with the Angular CLI

Some state management libraries, especially convention-based entity stores like NgRx Data, make assumptions about accessing server-side data. In the case of NgRx Data, the library wants to access the REST API via the /api path hosted on the same port as your Angular app. We must leverage the Angular CLI’s proxy feature to accomplish this during development.

Normally, HTTP requests are sent to our web server, and our API server should have the same URL. However, during development, we usually host both applications on two different ports of http://localhost. Certain libraries, including NgRx Data, require that HTTP calls be on the same port. This creates a challenge for creating a frictionless development experience. For this reason, the Angular CLI ships with a proxy feature with which you can direct the /api path to a different endpoint on your localhost. This way, you can use one port to serve your web app and your API requests...

Implementing a global spinner with NgRx/SignalState

In the Multi-step responsive forms section of Chapter 8, Recipes – Reusability, Forms, and Caching, and the Data tables with pagination section earlier in this chapter, I discussed the differences between localized spinners and global ones. A global spinner is the ultimate 80-20 solution to paper over UX issues stemming from UI elements not being ready for interaction while data loads. However, this will cause excessive full-screen interruptions in large applications with multiple on-screen components or background service workers loading data. In that case, most components will require local spinners instead.

With that in mind, let’s go after the 80-20 solution. We can use an HttpInterceptor to detect when an API call is made within the application. This allows us to show or hide a global spinner. However, if multiple calls are made concurrently, we must keep track of this, otherwise the global spinner may behave...

Rewriting Angular apps with NgRx/SignalStore

With Observables, the best subscription is the one you don’t have to make. Throughout this book, we used the async pipe, take(1), takeUntilDestroyed, and unsubscribe in ngOnDestroy to try and manage them. The sample code for this book has been through many reviews by various practitioners and experts over a period of six years. Every review highlighted some oversight or bug with the RxJS code.

The 3rd edition of the book provides a 99% bug-free implementation. I could never claim 100% due to the insane complexity of the RxJS ecosystem.

I take pride in not taking the easy way out. I do my best to provide realistic and complete examples for you, not just counters and to-do lists. However, these are still highly controlled and small-sized projects compared to what happens in real life. You rarely have time to go back and reevaluate your entire project. Mistakes get compounded over time. This is a sad reality of working with...

Summary

In this chapter, we completed going over all major Angular app design considerations using router-first architecture, along with our recipes, to implement a line-of-business app easily. We reviewed how to edit existing users, leverage a resolve guard to load user data, and hydrate and reuse a component in different contexts.

We implemented a master/detail view using auxiliary routes and demonstrated how to build data tables with pagination. We then learned how to implement NgRx/Store and NgRx/SignalStore using local-weather-app. We covered the available options within the NgRx ecosystem, including NgRx/Data, NgRx/ComponentStore, Akita, and Elf, and the differences between those options, so you can make informed decisions about what to include in your project.

We also implemented a pre-loading animation, so your app looks responsive when loading in slow connections. We also implemented a global spinner within the app to handle data pop-in-related UX issues. Finally...

Exercises

  1. Update UserTableComponent and related services in lemon-mart to leverage Elf entities and pagination to enable optimized handling of requests.
  2. Follow the guide on https://ngneat.github.io/elf/docs/features/pagination.
  3. Rewrite your Angular app with NgRx/SignalStore to be nearly Observable and RxJS operator-free with zero subscribe calls or async pipes.
  4. If you think this is a hilarious exercise tacked on toward the end of the book, give me a shoutout on my GitHub profile at https://github.com/duluca.

Further reading

Questions

Answer the following questions as best as possible to ensure you’ve understood the key concepts from this chapter without googling anything. Do you know if you got all the answers right? Visit https://angularforenterprise.com/self-assessment for more:

  1. What is a resolve guard?
  2. What are the benefits of router orchestration?
  3. What is an auxiliary route?
  4. How does NgRx differ from using RxJS/Subject?
  5. What’s the value of NgRx Data?
  6. In UserTableComponent, why do we use readonly isLoadingResults$: BehaviorSubject<Boolean> over a simple Boolean to drive the loading spinner?

Join our community on Discord

Join our community’s Discord space for discussions with the authors and other readers:

https://packt.link/AngularEnterpise3e

lock icon
The rest of the chapter is locked
You have been reading a chapter from
Angular for Enterprise Applications - Third Edition
Published in: Jan 2024Publisher: PacktISBN-13: 9781805127123
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
undefined
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at €14.99/month. Cancel anytime

Author (1)

author image
Doguhan Uluca

Doguhan Uluca is a Principal Fellow at Excella in Washington, D.C., where he leads strategic initiatives and delivers critical systems. He has technical expertise in usability, mobility, performance, scalability, cybersecurity, and architecture. He is the author of the Angular for Enterprise Application Development books, has spoken at over 30 conferences, and is an Angular GDE Alumni. Doguhan has delivered solutions for Silicon Valley startups, Fortune 50 companies, and the U.S. Federal Government, and he is passionate about contributing to open-source projects and teaching.
Read more about Doguhan Uluca