The Built-in `NgModel` Directive

The NgModel directive is an attribute directive. However, contrary to the previous two directives, NgClass and NgStyle, it does not change the appearance. Instead, it changes the behavior of the applied element.

Why NgModel is useful?

Whenever we have to implement a template-driven form, the NgModel is very helpful. It creates a two-way data binding for writing and reading values that are assigned to a particular control.

Template-driven forms

In Angular, there are two approaches listed below for designing the concept of a form:

  • Template-driven forms
  • Reactive forms

Template-driven forms rely mostly on implementing a template where the controls are handled through provided directives. One of them is the NgModel. It’s better to use this type of design instead of basic types of forms. This is because these designs are easier to set up. If we don’t have any complex logic or scalability issues, we can use template-driven forms.

Here’s a short example of what that would look like:

@Component({
  selector: 'app-form',
  template: `Your name: <input type="text" value="John" >`,
})
export class FormComponent {  
}

On the other hand, reactive forms provide a far more advanced way of handling the form. This design moves the logic from the template into the component’s class. There, we can set up the whole form along with the custom logic so that we can validate, set, and receive values. We can also reactively control the state and form value. Reactive forms are a perfect choice for more complex, scalable forms.

Here’s a short example of how to use a reactive form:

@Component({
  selector: 'app-form',
  template: `Your name: <input type="text" [formControl]="name">`,
})
export class FormComponent {  
	name = new FormControl('John');
}

Two-way data binding

In Angular, we often use data binding to propagate values from the component class into the template or to propagate an event (such as a click event) from the template into the component’s class.

Angular automatically manages those events to keep our page always up to date, no matter where the value change was propagated.

Let’s look at a couple of one-way data binding examples.

Here’s one example:

@Component({
  selector: 'app-form',
  template: `My name is {{ name }}`,
})
export class FormComponent {  
	name 'John';
}

And, here’s another below:

@Component({
  selector: 'app-form',
  template: `<button [disabled]="isDisabled"> click me </button>`,
})
export class FormComponent {  
	isDisabled = false;
}

This example uses a data binding with a value stored as a component’s property so that can be used in the template. Let’s remember that when the name property changes, Angular automatically update the data and refresh our view.

@Component({
  selector: 'app-form',
  template: `<button (click)="onClick()">Click me!</button>`,
})
export class FormComponent {  
	
	onClick() {
		console.log('hello there');
	}
}

This example also shows a data-binding mechanism that binds the events emitted from the template to the component’s properties, such as functions.

So, we’ve learned two ways to use data-binding.

  • From the data source to the template looks like this:

    {{data}}
    [target]="data"
    
  • From the template to the data source looks like this:

    (target)="function"
    

Now, let’s imagine we have an input, and we want to use it to populate a default value for the input. However, each time the input changes, we want this property to be updated with the newest data. So, we can say that this type of binding should work both ways—from the template to the component class and from the component class to the template. So, each time the value changes on either side, it should be synchronized and populated accordingly.

This type of binding is called two-way data binding, and it looks like this:

[(target)]="data"

Two-way data binding uses the notations [] and () to illustrate both ways the data can flow. We can also see the notation [()] which is known as “banana in the box.”

We’ll learn how to create a custom, two-way data binding later in this lesson, but now, let’s get back to the NgModel directive.

The NgModel syntax

Let’s now move to the syntax of the NgModel directive. It’s actually pretty simple once we understand the two-way data binding mechanism.

Here’s how we can use NgModel in the input, which is probably the most common case this directive uses:

<input [(ngModel)]="name">

This is simply a directive selector used in two-way data binding syntax. Let’s remember that this method of binding can only work with data-bound properties.

Get hands-on with 1200+ tech skills courses.