# Template-Driven Form

## About

{% embed url="<https://angular.dev/guide/forms/template-driven-forms>" %}

Angular infers the Form-Object (structure) from the DOM. (Better for more simple forms)

Some advantages include:

* More difficult to test.
* Have an asynchronous data-flow between View and Data model.
  * Data-flow is way more expensive, expecially in *(Model-to-View)*, when compared to Reactive-driven, since it needs to also call `NgModel` methods.
  * ***(View-to-Model)*** and ***(Model-to-view).** (*[*more info*](https://angular.dev/guide/forms#data-flow-in-template-driven-forms)*)*
* Rely on mutability of the Data Model with two-way binding to update the data model in the Component as changes are made in the Template.
  * Because there are no unique changes to track on the data model, change detection is less efficient at determining when updates are required.
* **Form validation is tied to template directives**, and must provide custom validator directives that wrap validation functions.
* Writing tests requires a detailed knowledge of the change detection process and an understanding of how directives run on each cycle to ensure that elements are queried, tested or change at the correct time. ([more info](https://angular.dev/guide/forms#testing-template-driven-forms))

## Examples

### Simple Setup - `NgModel` without `NgForm`

Very simple and useless.

In template-driven `NgModel` will automatically manage `FormControl` for you, so you don't have to create it.

```typescript
@Component({
    selector: "app-form-page",
    imports: [FormsModule],
    template: ` <input type="text" [(ngModel)]="username" /> `,
})
export class FormPageComponent {
    username = "";
}
```

### Regular Setup - `NgModel`

If there is no need to create class variables, handle form values ONLY inside the submit function.

Must provide `name=""` attributes to the inputs.

```typescript
@Component({
    selector: "app-form-page",
    imports: [FormsModule],
    template: `
        <form #loginForm="ngForm" (ngSubmit)="handleSubmit(loginForm)">
            <input type="text" name="username" ngModel />
            <input type="password" name="password" ngModel />
        </form>
    `,
})
export class FormPageComponent {
    protected handleSubmit(formData: NgForm) {
        console.log(formData.form.value.username);
    }
}
```

### Regular Setup - Submiting with `@ViewChild`

*Useful when you need to access the Form not only on submition.*

```typescript
@Component({
    selector: "app-form-page",
    imports: [FormsModule],
    template: `
        <form #loginForm="ngForm" (ngSubmit)="handleSubmit()">
            <input type="text" name="username" ngModel />
            <input type="password" name="password" ngModel />
        </form>
    `,
})
export class FormPageComponent {
    formData = viewChild<NgForm>("loginForm");

    protected handleSubmit() {
        this.formData();
    }
}
```

### Regular Setup - `NgModel` two-way binding

With two-way binding for class variables.

```typescript
@Component({
    selector: "app-form-page",
    imports: [FormsModule],
	template: `
        <form #loginForm="ngForm" (ngSubmit)="handleSubmit(loginForm)">
            <input type="text" [(ngModel)]="username" />
            <input type="password" [(ngModel)]="password" />
        </form>
    `,
})
export class FormPageComponent {
    username = "";
    password = "";

    protected handleSubmit(formData: NgForm) { ... }
}
```

### Validation Setup

*Only basic validation with the help of HTML5 validation.*

Angular under the hood will wrap itself on these HTML validators like `required`, `email`, etc, and do additional stuff.

Just adding them will not prevent the form submition.

```typescript
@Component({
    selector: "app-form-page",
    imports: [FormsModule],
	template: `
        <form #loginForm="ngForm" (ngSubmit)="handleSubmit()">
            <div>
                <input type="text" name="username" ngModel required #email="ngModel" />
                @if (!email.valid) {
                    <span>Invalid Username</span>
                }
            </div>
            <div>
                <input type="password" name="password" ngModel required minLength="6" />
            </div>
        </form>
    `,
})
export class FormPageComponent {
    handleSubmit(formData: NgForm) {
        if (!formData.form.valid) return;
        ...
    }
}
```
