Author avatar

Gaurav Singhal

Understanding Unidirectional Data Flow

Gaurav Singhal

  • Dec 5, 2019
  • 12 Min read
  • 148 Views
  • Dec 5, 2019
  • 12 Min read
  • 148 Views
Languages Frameworks and Tools
Angular

Introduction

Unidirectional data flow is an essential feature for working with the web-based applications.

According to the official Angular docs:

Angular's unidirectional data flow rule forbids updates to the view after it has been composed.

The term Data Flow refers to how the data will be compiled, i.e., from top to bottom or bottom to top. This means that when any changes are detected in the data, it will be processed for data manipulation.

What is Unidirectional Data Flow?

The reason data flows from top to bottom is that change detection strategies are also always performed from top to bottom for every single component, every single time, starting from the root component. This is awesome, as unidirectional data flow is more predictable than cycles. We always know where the data we use in our views comes from because it can only result from its component itself.

Change detection is one of the ways to perform an action using a specific event handler. The advantage of using this method is that we can modify the data of our app and make tons of changes with the whole tree of the current application.

The data that goes from the component classes into the output DOM—the data structures generated by the rendering process during the top-to-bottom rendering sweep of the component tree—is usually referred to as a unidirectional data flow.

Why We Need the Unidirectional Pattern

Whenever the rendering process in Angular is started, the different expression which is template-specific will be evaluated along with the different lifecycle hooks of the Angular component. After evaluating each of those expressions, the data will be rendered into the DOM itself, but keep in mind that the process of rendering the view does not modify the data itself at all.

If the process is not followed correctly while rendering the data into the DOM, it leads to major issues like performance overhead and so on.

This is why we need a unidirectional data flow mechanism, which ensures that the data is moving from top to bottom and that changes are propagated through the system.

Problems With Two-Way Data Binding

Previously, AngularJs supported two-way data binding, but Angular 2+ does not support it. This does not mean that we cannot use two-way data binding in Angular, but there are a several disadvantages:

  • Performance
  • Cascading modal updates
  • Boils down the event and property binding

Due to these issues, we should ignore using two-way binding; otherwise, it becomes too complex to manage large data into our Angular application.

How to Use Two-Way Data Binding

Angular 2+ can support the two-way data binding approach using the combination of event binding and property binding.

In order to understand, let's look at some simple syntax.

1
<input type=”text” [(ngModel)]=”value” />
html

Above is an example of a two-way binding mechanism that includes two different bindings:

  • () – Event binding
  • [] – Property binding

By using these two binding mechanisms, we can flow the data from the element and trigger an action attached to the element at the same time whenever the user performs an action.

Below is the complete example to demonstrate two-way data binding.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import { Component } from '@angular/core';

@Component({
  selector: 'my-app',
  template: `
    <table>
          <tr>
           <td>
              <input type="text" [(ngModel)]="propValue" />
             </td>
          </tr>
          <tr>
            Binding value is : {{ propValue }}
          </tr>
     </table>
  `,
  styleUrls: ['./app.component.css']
})

export class AppComponent {
  propValue = 'Angular Two-way data binding';
}
typescript

Let’s break down the above example to better understand.

(ngModel)

This is the kind of property for an element, which acts as a two-way data binding generator where the value of the text box will be updated whenever the user types anything into it.

Both the event and the property binding will be triggered at the same time, and the attached event handler will be activated.

{{ propValue }}

This is our component variable, which stores any string as a value and passes to the ngModel in order to get the updated value whenever the user changes the original value.

This is the one-way binding of data which we have created into our component in the example.

So now we have demonstrated a simple example of two-way binding and learned how it works.

One-Way Data Binding

While working with an Angular app, the term “one-way” data binding leads us to the idea of unidirectional data flow.

Angular 2 does have a form of two-way data binding; it does not prescribe a data flow architecture. One of its selling features is being patterned agnostic so that it will work with an MVC or a Flux architecture. Therefore, it's up to us as developers to choose an appropriate pattern to work with.

In the unidirectional or one-way data binding approach, the component should never change data directly. Instead, it should alert the desired change to the calling context and leave it up to the calling context to decide whether or not the desired change should be applied to the view-model.

Basically, the one-way data binding mechanism flows the data from the component to view, and from the view, we can render the desired value.

Types of Unidirectional Data Bindings

In order to implement one-way data binding i Angular, we have plenty of options:

  • Property binding
  • Class binding
  • Style binding
  • Attribute binding
  • Interpolation

These are all the types of one-way data binding, and using such types, we can implement one-way data flow from our component to the view.

Let’s look at an example of each type of one-way binding.

Property Binding

This is the simplest way to bind the component properties or modal values to the view’s different HTML element.

Here in this type, the HTML element’s property will be used for the binding, and we can use brackets [ ] around the property, like this: [property].

Let’s understand property binding with an example.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import { Component } from '@angular/core';

@Component({
  selector: 'my-app',
  template: `
    <table>
      <tr>
        <td>
        <label [innerHtml]="propValue"></label>
        </td>
      </tr>
    </table>
  `,
  styleUrls: ['./app.component.css']
})

export class AppComponent {
  propValue = 'Angular Two-way data binding';
}
typescript

Here in this example, we have used label element, and along with the element we have used a property called innerHtml.Notice that we have used [] along with the property name, which defines that we have used property binding that accepts the modal or component value from the component and renders it.

This is how we can use property binding in order to use component value into the view.

Class Binding

Class binding is used to add or remove different class names from an HTML element based on the value coming from the component's modal or property.

In order to apply class binding, there is one prefix called class. For example, if we want to apply the class name mytext, then we can apply class binding, as explained below.

Let’s look at a simple example using the class binding mechanism.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import { Component } from '@angular/core';

@Component({
  selector: 'my-app',
  template: `
<table>
      <tr>
        <td>
        <label [class.mylabel]="isLabel" [innerHtml]="propValue"></label>
        </td>
      </tr>
    </table>
  `,
  styleUrls: ['./app.component.css']
})

export class AppComponent {
  propValue = 'Angular Two-way data binding';
  isLabel: boolean = true;
}
typescript

And the stylesheet can be defined in the different file, like this:

1
2
3
.mylabel {
  font-size: 25px
}
css

In the above code, the snippet is just a simple CSS stylesheet which contains a single class, myLabel, that we have used to bind the class.

This is how to use class binding, and using such an approach we can add or remove different classes conditionally.

Style Binding

We have already seen how to apply class binding. Sometimes we may need to bind the styles to be inline directly to the HTML element.

In order to apply inline styles using style binding, we should use the prefix style followed by the (.) dot operator and the name of the style.

Let’s move to the simple example which demonstrates the usage of style binding.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import { Component } from '@angular/core';

@Component({
  selector: 'my-app',
  template: `
    <table>
      <tr>
        <td>
        <h3 [style.font-size]="45" [innerHtml]="propValue"></h3>
        </td>
      </tr>
    </table>
  `,
  styleUrls: ['./app.component.css']
})

export class AppComponent {
  propValue = 'Angular Two-way data binding';
}
typescript

Here in the above code snippet, we have an element called h3, and along with the element, we need to apply a font-size property. Then we can make use of style binding.

In the example, we have used [style.font-size] along with the specific value, so that the styling will be applied to that element and it will be rendered into the DOM.

Attribute Binding

Attribute binding is used to bind the different attribute properties to the view’s element. It is used to bind the different attributes conditionally when we have component/modal properties based on the business requirement from the component to the view.

To apply attribute binding, we need to use the prefix attr followed by the (.) dot operator and the attribute name.

Now let’s jump to the example in order to understand how attribute binding works.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import { Component } from '@angular/core';

@Component({
  selector: 'my-app',
  template: `
<table>
      <tr>
        <td>
        <h3 [attr.align]="right" [innerHtml]="propValue"></h3>
        </td>
      </tr>
    </table>
  `,
  styleUrls: ['./app.component.css']
})

export class AppComponent {
  propValue = 'Angular Two-way data binding';
}
typescript

As you can see in the example, we have element <h3>. If we want to apply attribute align, then we can surround it with the binding like [attr.align] followed by the appropriate value.

This is how we can apply various supported attributes to the element using the attribute binding mechanism.

Interpolation

Interpolation is a commonly used binding mechanism which is also called as one-way data binding.

Generally, interpolation is used to bind the one-way component property to the view and not vice-versa.

In order to use interpolation, we need to enclose our component’s property with curly braces {{ }}, and the value will be rendered into the DOM.

Let’s jump into the example and see how interpolation works.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import { Component } from '@angular/core';

@Component({
  selector: 'my-app',
  template: `
    <span>
      {{ propValue }}
    </span>
  `,
  styleUrls: ['./app.component.css']
})

export class AppComponent {
  propValue = 'Angular Two-way data binding';
}
typescript

Here in this example, we have one component property called propValue, and into the view, we have span element and used {{ }} brackets in order to render the value within the span.

Interpolation will always be a way of one-way data binding to bind the value from component properties to the view.

Conclusion

In this guide, we have learned about unidirectional data bindings, including what a unidirectional data flow is, as well as one-way and two-way data binding approaches and a detailed list of one-way binding types and how to use them.

That’s a wrap for now. Stay tuned for more interesting and detailed articles.

0