Categories
Angular JavaScript

Introduction to Angular Reactive Forms

Angular is a popular front-end framework made by Google. Like other popular front-end frameworks, it uses a component-based architecture to structure apps.

In this article, we’ll look at the basics of creating reactive forms with Angular.

Reactive Forms

Reactive forms use an explicit and immutable approach to managing the state of a form at a given point in time. Each change returns a new state, which maintains the integrity of the model between changes.

It’s also easier to test because the data is consistent and predictable.

We can create a Reactive form as follows:

app.module.ts :

import { BrowserModule } from "@angular/platform-browser";  
import { NgModule } from "@angular/core";  
import { ReactiveFormsModule } from "@angular/forms";  
import { AppComponent } from "./app.component";

@NgModule({  
  declarations: [AppComponent],  
  imports: [BrowserModule, ReactiveFormsModule],  
  providers: [],  
  bootstrap: [AppComponent]  
})  
export class AppModule {}

app.component.ts :

import { Component } from "@angular/core";  
import { FormControl } from "@angular/forms";

@Component({  
  selector: "app-root",  
  templateUrl: "./app.component.html",  
  styleUrls: ["./app.component.css"]  
})  
export class AppComponent {  
  nameControl = new FormControl("");  
}

app.component.html :

<input type="text" [formControl]="nameControl" />  
<p>{{ nameControl.value }}</p>

In the code above, we imported the ReactiveFormsModule in app.module.ts .

Then in AppComponent , we added a FormControl called nameControl .

Then we connect our input element to nameControl by using the formControl property.

To display the value we typed in, we reference the nameControl ‘s value property as we did with the p element.

Replacing a Form Control Value

We can call the setValue method on a FormControl to replace the value of it.

For example, we can write the following code:

app.component.ts

import { Component } from "@angular/core";  
import { FormControl } from "@angular/forms";

@Component({  
  selector: "app-root",  
  templateUrl: "./app.component.html",  
  styleUrls: ["./app.component.css"]  
})  
export class AppComponent {  
  nameControl = new FormControl(""); 

  updateName() {  
    this.nameControl.setValue("Jane");  
  }  
}

app.component.html :

<input type="text" [formControl]="nameControl" />  
<button (click)="updateName()">Update Name</button>

In the code above, we have the updateName method which calls setValue to set the value of FormControl .

When we click the button, we’ll see Jane entered in the input.

Grouping Form Controls

We can create a FormGroup to group form controls together.

For example, we can use it as follows:

app.component.ts :

import { Component } from "@angular/core";  
import { FormControl, FormGroup } from "@angular/forms";

@Component({  
  selector: "app-root",  
  templateUrl: "./app.component.html",  
  styleUrls: ["./app.component.css"]  
})  
export class AppComponent {  
  personForm = new FormGroup({  
    nameControl: new FormControl("")  
  });  
}

app.component.html :

<form [formGroup]="personForm">  
  <input type="text" formControlName="nameControl" />  
</form>

We bound the form to personForm by using the formGroup property.

Then we set the form control in the form group by using the formControlName property.

Submitting Form Data

We can submit data entered into a Reactive form by attaching an onSubmit handler to our form.

To do that we can write the following:

app.component.ts :

import { Component } from "@angular/core";  
import { FormControl, FormGroup } from "@angular/forms";

@Component({  
  selector: "app-root",  
  templateUrl: "./app.component.html",  
  styleUrls: ["./app.component.css"]  
})  
export class AppComponent {  
  personForm = new FormGroup({  
    nameControl: new FormControl("")  
  }); onSubmit() {  
    console.log(this.personForm.value);  
  }  
}

app.component.html :

<form [formGroup]="personForm" (ngSubmit)="onSubmit()">  
  <input type="text" formControlName="nameControl" />  
  <button type="submit">Submit</button>  
</form>

In the code above, we have the onSubmit handler, which gets the value of all the fields entered by accessing the value property of the form group.

When we click Submit, we should see what we typed in.

To disable the Submit button if the form isn’t valid, we can write:

app.component.html:

<button type="submit" [disabled]="!personForm.valid">Submit</button>

to set the disabled property of the button when the personForm ‘s valid value.

Creating Nested Form Groups

We can nest form groups. For example, we can write the following code to do that:

app.component.ts :

import { Component } from "@angular/core";  
import { FormControl, FormGroup } from "@angular/forms";

@Component({  
  selector: "app-root",  
  templateUrl: "./app.component.html",  
  styleUrls: ["./app.component.css"]  
})  
export class AppComponent {  
  personForm = new FormGroup({  
    name: new FormControl(""),  
    address: new FormGroup({  
      street: new FormControl("")  
    })  
  }); onSubmit() {  
    console.log(this.personForm.value);  
  }  
}

app.component.html :

<form [formGroup]="personForm" (ngSubmit)="onSubmit()">  
  <input type="text" formControlName="name" placeholder="Name" />  
  <div formGroupName="address">  
    <input type="text" formControlName="street" placeholder="Street" />  
  </div>  
  <button type="submit">Submit</button>  
</form>

In the code above, we have the personForm form group with the name FormControl in the root.

Then we added the address FormGroup , which has the street FormControl inside.

In app.component.html , we bind the form to the personForm FormGroup as usual, but we have an extra div to bind the div and what’s inside to the address FormGroup .

Then we bind the street FormControl to our input inside.

Conclusion

We can create FormControl s and bind input elements to them.

Also, we can create FormGroup s and bind forms to them.

FormGroup s can be nested within each other.

We can access a FormGroup and FormControl ‘s values with the value property.

Categories
JavaScript JavaScript Basics

JavaScript Array Tips — Removing Duplicates and Emptying Arrays

JavaScript, like any other programming languages, have many handy tricks that let us write our programs more easily. In this article, we will look at how to do different things that involve arrays, like removing falsy values, getting random values from an array, and reversing arrays.

Removing Falsy Values

In JavaScript, falsy values include 0, empty string, null , undefined , false and NaN . We often run into these values when we’re processing arrays and they may cause errors.

Values like null , undefined , and NaN often are unexpected and it’s easier if we eliminate them from an array before doing anything else to them.

We can do this with a few ways which involve using the filter method that is available to arrays. The filter method takes in a callback function.

The callback function that has 2 parameters, the first one is an array entry and the second one is the index of the array that’s being iterated to by the filter method. The filter method filter let us defined what we want to keep and return a new array with the entries kept according to the boolean expression we return.

Any function that’s defined that takes at least the value and returns a boolean value can be used as the callback function, so one way we can use the filter method to filter out is to use the Boolean factory function, which takes in any object in its first argument and returns true if it’s truthy and false if it’s falsy. If true is returned from the callback function then the item will be kept.

Otherwise, it will discard the value in the array it returns. For example, we can use the Boolean function by passing in straight into the filter method like we do in the following code:

let arr = [0, 'yellow', '', NaN, 1, true, undefined, 'orange', false];  
arr = arr.filter(Boolean);  
console.log(arr);

Then we get the following output from the console.log :

["yellow", 1, true, "orange"]

We can also use the exclamation mark operator twice to coerce truthy values to true and falsy values to false . We just put the exclamation 2 times in front of value to do this, so we can use the operator like in the following code to filter out falsy values:

let arr = [0, 'yellow', '', NaN, 1, true, undefined, 'orange', false];  
arr = arr.filter(a => !!a);  
console.log(arr);

If we run the code above, we should get the same thing as we did before. Likewise, we can pass in a function that returns the value from the Boolean function instead of passing in Boolean function directly to the filter method to make the expression more clear:

let arr = [0, 'yellow', '', NaN, 1, true, undefined, 'orange', false];  
arr = arr.filter(a => Boolean(a));  
console.log(arr);

We should get the same thing as we did before if we run the code above.

Get a Value Randomly from an Array

To get a random value from an array, we can use the Math.random method to get a random index in addition to some other code.

We more code than just calling the Math.random method because it only returns a random number between 0 and 1, which means that it returns a decimal number between 0 and 1, which we don’t want.

This means that it has to be multiplied by our array’s length to get a value between 0 and the length of our array. Then we need call Math.floor on that result to round it down to the nearest integer.

We can use the Math.random method like in the following code:

let arr = ['yellow', 'orange', 'blue', 'purple', 'green'];  
const chosenValue = arr[(Math.floor(Math.random() * (arr.length)))]  
console.log(chosenValue);

The code above generates the index by running Math.random() * (arr.length) , which will range from 0 to the length of the array. Then we round it down with the Math.floor method which takes a number that we want to round down so that we get the number rounded down to the nearest integer since we don’t want non-integer numbers.

Then we can pass that into the brackets to get the index that was generated.

Reversing an Array

We can reverse an array by using the reverse method that comes with JavaScript array objects. It takes no arguments and reverses an array in place. For example, we can use it as in the following code:

let arr = ['yellow', 'orange', 'blue', 'purple', 'green'];  
arr.reverse();  
console.log(arr);

Then we get:

["green", "purple", "blue", "orange", "yellow"]

from the console.log output above. The reverse method works with any primitive objects in addition to objects. For example, if we have:

let arr = [{  
  a: 1  
}, {  
  b: 2  
}, {  
  c: 3  
}];  
arr.reverse();  
console.log(arr);

Then we get back the following output from the console.log :

[  
  {  
    "c": 3  
  },  
  {  
    "b": 2  
  },  
  {  
    "a": 1  
  }  
]

The reverse method also works with any object that has numerical keys. For example, if we have:

let arrLikeObj = {  
  0: 'a',  
  1: 'b',  
  2: 'c',  
  length: 3  
}  
Array.prototype.reverse.call(arrLikeObj);  
console.log(arrLikeObj);

Then we get back the following output from the console.log :

{  
  "0": "c",  
  "1": "b",  
  "2": "a",  
  "length": 3  
}

As long as the object has numerical keys starting from 0 and increments by 1 from there and a length property, the code above will work. We can also use the apply method to do the same thing like in the following code:

let arrLikeObj = {  
  0: 'a',  
  1: 'b',  
  2: 'c',  
  length: 3  
}  
Array.prototype.reverse.apply(arrLikeObj);  
console.log(JSON.stringify(arrLikeObj, (key, value) => value, 2));

Then once again we get back the following output from the console.log :

{  
  "0": "c",  
  "1": "b",  
  "2": "a",  
  "length": 3  
}

Conclusion

In JavaScript, falsy values include 0, empty string, null , undefined , false and NaN . We often run into these values when we’re processing arrays and they may cause errors. Values like null , undefined , and NaN often are unexpected and it’s easier if we eliminate them from an array before doing anything else to them.

We can do this with a few ways which involve using the filter method that are available to arrays.

We can use the Boolean function or applying the exclamation mark twice to convert an object into a boolean value. To reverse an array, we can use call the reverse method on an array to reverse it.

The reverse method also works with any object that has numerical keys starting from 0 and increments by 1 and a length property. We can get a random entry from an array by using Math.random multiplied by the array’s length and Math.floor methods.

Categories
JavaScript

JavaScript Events Handlers — Mouse Enter and Leave Events

In JavaScript, events are actions that happen in an app. They’re triggered by various things like inputs being entered, forms being submitted, changes in an element like resizing, or errors that happen when an app is running, etc. We can assign an event handler to handle these events. Events that happen to DOM elements can be handled by assigning an event handler to properties of the DOM object for the corresponding events. In this article, we’ll look at the mouseenter and mouseleave events.

onmouseenter

The mouseenter event is fired when a pointing device like a mouse is moved over the element that has the onmouseenter event listener function assigned to it. It’s similar to the mouseover event, but the mouseenter event doesn’t bubble and it isn’t sent to the descendants when the pointer is moved from one of element’s descendant’s physical space to its own physical space.

This means that the mouseenter event is fired whether the mouse moves to another element no matter where it is in the hierarchy. Therefore, the mouseenter event may be fired many times, which can cause significant performance problems. If we need to listen to events in the whole element tree when the mouse is over a big element with lots of descendants, then it’s better to use the mouseover event.

When combined with the mouseleave event, which is fired when the mouse leaves an element, the mouseenter event acts in a way that’s very similar to the CSS :hover pseudo-class.

For example, we can use it to create a peeping effect on an image where we show a part of an image when the mouse pointer hovers over a part of an image.

First, we add the HTML code for the image and a black box for hiding the image. Also, we add a circle div element to show part of the image that we hover over. To do this, we put in the following code:

<div class='container'>  
  <div class="view" hidden></div>  
  <img src='https://images.unsplash.com/photo-1503066211613-c17ebc9daef0?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1500&q=80'></div>

The .container div is added for showing the black box for covering up the image. The .view div is the circle for us to have the peeping effect to reveal part of the image as we hover over it, and the img element has the image itself.

Next, we add the CSS code to style div elements like we just described by adding the following CSS code:

.container {  
  background: black;  
  width: 500px;  
}.view {  
  position: absolute;  
  width: 200px;  
  height: 200px;  
  background: white;  
  border-radius: 50%;  
}img {  
  mix-blend-mode: darken;  
  width: 500px;  
}

Then finally, we add the JavaScript code to do what we just described:

const img = document.querySelector('img');  
const view = document.querySelector('.view');  
const container = document.querySelector('.container');
const showView = (event) => {  
  view.removeAttribute('hidden');  
  view.style.left = event.clientX - 50 + 'px';  
  view.style.top = event.clientY - 50 + 'px';  
  event.preventDefault();  
}

const moveView = (event) => {  
  view.style.left = event.clientX - 50 + 'px';  
  view.style.top = event.clientY - 50 + 'px';  
}

container.onmousemove = moveView;  
container.onmouseenter = showView;

In the code above, we get the .container element by using the querySelector method. We do the same with the img and .view elements. Once we did that, we write the event handler functions.

The onmouseenter property of the .container div element is set to the showView function, which is runs when the mouse button is down. Inside the function, we remove the hidden attribute from the .view div element to reveal the image underneath the div . From the event parameter, which has the Event object, we get the clientX and clientY properties, which has the mouse coordinates of the click location. We set that to the position of the view DOM object which represents the .view element. Then we called event.preventDefault() to stop the default action since we already did the revealing with the code before it.

The onmousemove event handler of the .container div element is set to the moveView function, which handles the mousemove event. The event is fired when the mouse moves. In the function, we set the .view element to the position of where the mouse pointer is currently located, again with the clientX and clientY properties of the event parameter, which is the MouseEvent object.

Once we did all that, when we hover our mouse over the black box, then we reveal that part of the image underneath.

onmouseleave

The onmouseleave property of a DOM element lets us assign an event handler to handle the mouseleave event. The event is fired when the pointing device like a mouse is moved off the element that has the listener attached.

This means that the mouseleave event is fired whether the mouse moves to another element no matter where it is in the hierarchy. Therefore, the mouseleave event may be fired many times, which can cause significant performance problems. If we need to listen to events in the whole element tree when the mouse is over a big element with lots of descendants, then it’s better to use the mouseout event.

For example, we can use it to track whether the mouse is over an element or not. First, we add an HTML div element as we do in the following code:

<div id='log'></div>

Then we add some CSS to add a border on the div and resize it:

#log {  
  width: 300px;  
  height: 150px;  
  border: 1px solid black;  
}

Finally, we can add the following JavaScript code to set different text depending on whether the mouse is over the log div or not:

const log = document.getElementById('log');  
log.onmouseover = () => {  
  log.textContent = 'Mouse over'  
}

log.onmouseleave = () => {  
  log.textContent = 'Mouse left'  
}

Once we did that, we should see the ‘Mouse over’ message in the box when our mouse is over the box and ‘Mouse left’ when our mouse pointer left the box.

Another example of using the mouseleave event is for showing different images depending on whether our mouse is over an image element or not. We just have the change the HTML as we do in the following code:

<img src='https://images.unsplash.com/photo-1503066211613-c17ebc9daef0?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1500&q=80'>

Then the CSS we change to the following:

img {  
  width: 300px;  
}

Finally, in the JavaScript code, we change the src of the img element in the onmouseover and onmouseleave event handler functions as we do in the following code:

const img = document.querySelector('img');  
img.onmouseover = () => {  
  img.src = 'https://images.unsplash.com/photo-1503066211613-c17ebc9daef0?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1500&q=80'  
}

img.onmouseleave = () => {  
  img.src = 'https://images.unsplash.com/photo-1546182990-dffeafbe841d?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=740&q=80' 
}

After that, we’ll get different images as we hover our mouse over or leave the img element.

The mouseenter event is fired when a pointing device like a mouse is moved over the element that has the onmouseenter event listener function assigned to it. It’s similar to the mouseover event, but the mouseenter event doesn’t bubble and it isn’t sent to the descendants when the pointer is moved from one of the element’s descendant’s physical space to its own physical space.

The onmouseleave property of a DOM element lets us assign an event handler to handle the mouseleave event. The event is fired when the pointing device like a mouse is moved off the element that has the listener attached.

We can use event handler functions for both events to do various things like showing and hiding items when the mouse pointer is over something or not.

Categories
JavaScript React

Built-in React Hooks —useLayoutEffect and useDebugValue

React is a library for creating front end views. It has a big ecosystem of libraries that work with it. Also, we can use it to enhance existing apps.

In this article, we look at the useLayoutEffect and useDebugValue hooks.

useLayoutEffect

useLayoutEffect has an identical signature to useEffect , but it fires synchronously after all DOM mutations are done.

This is useful for reading layout from the DOM and synchronously re-render.

Updates inside useLayoutEffect will be flushed synchronously before the browser has a chance to paint.

To prevent blocking visual updates, we should use useEffect whenever possible.

useLayoutEffect fires in the same phase as componentDidMount and componentDidUpdate .

We should only use useLayoutEffect if useEffect isn’t working properly.

If server rendering is used, the useLayoutEffect nor useEffect are run until the JavaScript is downloaded.

React warns when server-rendered component contains useLayourEffect .

To exclude components that need layout effects from server-rendered HTML, we render it conditionally with showChild && <Child /> and defer showing it with useEffect(() => { setShowChild(true); }, []).

Then the UI won’t appear broken before rendering is done.

For example, we can render synchronous with useLayoutEffect as follows:

function App() {  
  const [value, setValue] = React.useState(0);  
  React.useLayoutEffect(() => {  
    if (value === 0) {  
      setValue(10 + Math.random() * 200);  
    }  
  }, [value]); return (  
    <>  
      <button onClick={() => setValue(0)}>Random Value</button>  
      <p>{value}</p>  
    </>  
  );  
}

Since value is set initially to 0, we want to update that first before rendering, so we use useLayoutEffect hook and call setValue in the callback.

Also, since we set value to 0 when clicking the button, we want to only show the value when value when it’s not 0, so useLayoutEffect will prevent 0 from being shown.

useDebugValue

useDebugValue is used to display a label for custom hooks in React DevTools.

It takes any value that we want to display.

For example, we can use it as follows:

import React, { useEffect, useState } from "react";  
import ReactDOM from "react-dom";  
const useDelayedMessage = (msg, delay) => {  
  const [message, setMessage] = useState("");  
  useEffect(() => {  
    setTimeout(() => {  
      setMessage(msg);  
    }, delay);  
  });  
  React.useDebugValue(message ? "Message Set" : "Message not set");  
  return message;  
};

function App() {  
  const delayedMessage = useDelayedMessage("foo", 1500);  
  return <div>{delayedMessage}</div>;  
}

Since we have:

React.useDebugValue(message ? "Message Set" : "Message not set");

in React DevTools, we’ll see the Message not set message when the page first loads, and then when message is set after the delay , then we see Message set .

This hook is useful for custom hooks that are part of shared libraries.

Defer formatting debug values

In some cases formatting, a value for display may be an expensive operation.

Therefore, useDebugValue accepts a formatting function as an optional second parameter. The function is only called if the hooks are inspected.

It receives the debug value as a parameter and returns the formatted display value.

For example, we can write:

import React, { useEffect, useState } from "react";  
import ReactDOM from "react-dom";  
const useDelayedMessage = (msg, delay) => {  
  const [message, setMessage] = useState("");  
  useEffect(() => {  
    setTimeout(() => {  
      setMessage(msg);  
    }, delay);  
  });  
  React.useDebugValue(message, message =>  
    message ? "Message Set" : "Message not set"  
  );  
  return message;  
};

function App() {  
  const delayedMessage = useDelayedMessage("foo", 1500);  
  return <div>{delayedMessage}</div>;  
}

In the code above, we have:

React.useDebugValue(message, message =>  
    message ? "Message Set" : "Message not set"  
  );

which runs the formatting function in the second argument when it’s inspected.

The message parameter has the same value as message returned from useState .

Conclusion

We can use the useLayoutEffect hook to synchronous run code after all DOM mutations are done.

useDebugValue hook is handy for debugging with React DevTools since it lets us display something in the DevTools console as the hook runs.

Categories
Angular JavaScript

Introduction to Angular Forms

Angular is a popular front-end framework made by Google. Like other popular front-end frameworks, it uses a component-based architecture to structure apps.

In this article, we’ll look at the basics of creating forms with Angular.

Different Kinds of Forms

Angular provides 2 different approaches to handling user input through forms.

They are either reactive or template-driven. They both capture events from the view, validate their user input, and create a form model and data model to update, and provide a way to track changes.

Reactive forms are more robust. They’re more scalable, reusable and testable.

Template-driven forms are useful for adding a simple form to an app. They’re easy to add, but they don’t scale as well as reactive forms.

Common Foundation

Both kinds of forms share the following building blocks:

  • FormControl — tracks the value and validation status of individual form controls
  • FormGroup — tracks the same value and status for a collection of form controls
  • FormArray — tracks the same value and status for an array of form control.s.
  • ControlValueAccessor — creates a bridge between Angular FormControl instances and native DOM elements.

Form Model Setup

We can set up the form model of a Reactive form by setting the formControl property of an input element.

For example, we can write the following code:

app.module.ts :

import { BrowserModule } from "@angular/platform-browser";  
import { NgModule } from "@angular/core";  
import { ReactiveFormsModule } from "@angular/forms";  
import { AppComponent } from "./app.component";

@NgModule({  
  declarations: [AppComponent],  
  imports: [BrowserModule, ReactiveFormsModule],  
  providers: [],  
  bootstrap: [AppComponent]  
})  
export class AppModule {}

app.component.ts :

import { Component } from "@angular/core";  
import { FormControl } from "@angular/forms";

@Component({  
  selector: "app-root",  
  templateUrl: "./app.component.html",  
  styleUrls: ["./app.component.css"]  
})  
export class AppComponent {  
  nameControl = new FormControl("");  
}

app.component.html :

<input type="text" [formControl]="nameControl" />

In the code above, we added the ReactiveFormsModule to our AppModule .

Then we created nameControl in AppComponent .

Finally, we set the formControl property to nameControl to connect the input to the FomControl .

Setup in Template-Driven Forms

We can use the ngModel directive to bind our input value to the a field in our component.

For example, we can write the following:

app.module.ts :

import { BrowserModule } from "@angular/platform-browser";  
import { NgModule } from "@angular/core";  
import { FormsModule } from "@angular/forms";  
import { AppComponent } from "./app.component";

@NgModule({  
  declarations: [AppComponent],  
  imports: [BrowserModule, FormsModule],  
  providers: [],  
  bootstrap: [AppComponent]  
})  
export class AppModule {}

app.component.ts :

import { Component } from "@angular/core";

@Component({  
  selector: "app-root",  
  templateUrl: "./app.component.html",  
  styleUrls: ["./app.component.css"]  
})  
export class AppComponent {  
  name: string;  
}

app.component.html :

<input type="text" [(ngModel)]="name" />

In the code above, we imported the FormsModule in app.module.ts .

Then we created the name field in AppComponent to bind the data to the field.

Then we bind our input’s value to name via ngModel .

Both Reactive and Template-Driven forms provide 2 way binding between the model and the input.

Data Flow in Reactive Forms

From view to model, the data flow follows the following steps:

  1. User types something into the input
  2. Form input emits an input event
  3. Control value accessor listens for events on the form input and sends the new value to the FormControl instance.
  4. The FormControl instance emits the new value through the valueChanges observable.
  5. Subscribes to valueChanges receive the new value

From model to view, the flow is as follows:

  1. The user calls the nameControl.setValue method to update the FormControl value
  2. The FormControl instance emits the new value through the valueChanges observable.
  3. Any subscribers to the valueChanges observable receive the new value
  4. The control value accessor on the form input element updates the element with the new value

Data Flow in Template-Driven Forms

The data from the view to the model in template-driven forms are as follows:

  1. User types something into the input element.
  2. The input element emits an input event with the value typed in
  3. The control value accessor attached to the input triggers the setValue method on the FormControl instance
  4. The FormControl instance emits the new value through valueChanges observable
  5. Any subscribers to the valueChanges observable receives the new value
  6. The control value accessor also calls NgModel.viewToModelUpdate method which emits an ngModelChange event
  7. ngModelChanges triggers model value update

From model to view, the flow is as follows:

  1. The value is updated in the component
  2. Change detection begins
  3. ngOnChanges is called on the NgModel directive instance because the input value has changed
  4. ngOnChanges queues an async task to set the value of the FormControl instance
  5. Change detection completes
  6. The task to set FormControl instance value is run on next tick
  7. FormControl instance emits the latest change through the valueChanges observable
  8. Any subscribers to the valueChanges observable receives the new value
  9. Control value accessor updates the form input element in the view

Conclusion

We can create Angular forms as Reactive or Template-Driven forms.

Reactive forms are more robust and Template-Driven forms are suitable for simple forms.

They both have the same parts. The control value accessor takes the input value and sets it to the model.