Reactive forms with smart dumb components

Fanis Prodromou
Angular Athens
Published in
5 min readJan 14, 2019
source: https://www.cinemablend.com

In this post, we will try together to build a form consisting of different components and we will try various implementations to achieve the best architecture.
The final approach will incorporate the smart dumb pattern.

What are we gonna do? What are we gonna implement? The following…

Let’s examine this a bit. It has a Basic Info, an Address, and a Credit Cards sections. In order to follow the Smart Dumb pattern, we will have them as dumb components. But wait, don’t we need to have a smart component too? Of course. This will be our fourth component.

Quick reference on smart — dumb components

Let’s try to understand the terms smart-dumb from the responsibilities point of view.

Smart is responsible for how things work.

  • Orchestrates the data from HTTP services
  • Provide the data to dumb components, via property binding
  • Has no DOM markup or styles

Dumb is responsible for how things look.

  • Has no dependencies on services

The smart-dumb is also called container-presentation

The problem

We love solving problems, don’t we? Let’s face it then :)

Each form has different validation rules and we want to have one single point to check if all the forms are valid. We want to know when to disable a button if the form is invalid. We do not want to invoke the HTTP call if the form is invalid.
Furthermore, we want to unit test each component separately.

Let’s start investigating different approaches

Approach #1

We have three different forms and we want to have a single point to track the validity status. Let’s create then a formGroup which will have nested formGroups.

The validity of each formControl bubbles up to his parent formGroup or formArray which in turn bubbles up to the root formGroup. This is very handy as it allows us handle easy the validity status

Notice that we’ve created the basic and address formGroups, and creditCards formArray.
We now need to create the presentation components and provide them with the relevant formGroup or formArray.
Let’s see first the orchestration of the components in the smart component

The app-customer-basic, app-customer-address and app-customer-credit-cards are our nested components. Notice that we provide the relevant formGroup or formArray by using the theForm.get('')`.

Let’s see the code of those nested components

Basic Component

Address Component

Credit Cards Components

The dumb components are indeed very lean and they do only one thing (SRP principle) PRESENTATION. Let’s examine the pros and cons

pros -cons Approach #1

pros

  1. The smart component is automatically updated of the form status
  2. The dumb components are lean and easy to maintain

cons

  1. Hard to identify what is the model of each component. The HTML code of the dumb components is bound with the form model of the smart component.
  2. We should re-create the form of each dumb component once more for unit testing
  3. We should re-create the form model of the credit cards in order to implement the addCreditCard and removeCreditCard

Approach #2

Let’s now focus on the 3rd point of the above cons list and try not to re-create the form model for the addCreditCard and removeCreditCard actions.

In essence we will move the form initialization from the smart component to the dumb component

Notice that we still set the formArray in smart component. This will help us re-use the array’s reference later on

This approach gives us the flexibility to implement the addCreditcard and removeCreditCard without re-creating the form model. We did a mini refactoring of our code. Let’s see what we’ve achieved.

pros -cons Approach #2

pros

  1. The smart component is automatically updated of the form status
  2. The dumb components are lean and easy to maintain
  3. Responsible for the form model is only the credit cards component

cons

  1. Hard to identify what is the model of each component. The HTML code of the dumb components is bound with the form model of the smart component.
  2. We should re-create the form of each dumb component once more for unit testing
  3. Inconsistency of the initialization of the form model in components.

Snap!! We still have the same amount of cons! We are not yet there! Let’s try more!!

Approach #3

So far, the smart component initializes the basic and address formGroups but not the creditCards formArray.

Let’s try in this approach to have consistent formGroup initialization. We will remove completely the initialization from smart component and have it only in dumb components. But wait!! How are we gonna get the status of the dumb components? Well, we will utilize the power of ViewChild decorator.

I won’t upload the code of the dumb components as they are almost the same. The only difference is that we have to remove the @input decorator

The ViewChild decorator is very handy as it queries DOM elements and gets the state of them. If we use it with the class name, we get the class instance and not the element reference. This is very useful for our case.

Notice that we use the combineLatest rxjs operator. Read more here https://www.learnrxjs.io/operators/combination/combinelatest.html

The combileLatest operator is best used when you have multiple, long-lived observables that rely on each other for some calculation or determination.

pros — cons Approach #3

pros

  1. The dumb components are lean and easy to maintain
  2. Responsible for the form model is each smart dumb component
  3. Easy to identify what is the model of each dumb component as we lower the distance
  4. We shouldn’t re-create the form of each dumb component for the unit testing
  5. Consistent form initialization
  6. The smart component is automatically updated with the form status of each dumb component

cons

  1. Requires orchestration on the smart component
  2. The status requires to be evaluated on the smart component, while we could just bound it on the template

Conclusion

The smart dumb pattern is excellent! The reactive forms are amazing. Having both it’s tricky and requires attention for the best outcome.

Having read this article you might think that the 3rd approach is the best way. Well, not always. It’s very good for this scenario but other scenarios would require the first approach.

I hope you enjoyed the article :)

Here you will find the final approach https://github.com/profanis/angular-athens-reactive-forms

Follow me on twitter https://twitter.com/prodromouf

--

--

Fanis Prodromou
Angular Athens

I am a senior software engineer who loves scuba diving and hiking. A dog type person who owns two cats