Part 3: Maximizing Angular Forms with Dynamic Custom Form Controls and Styling
Tags: angular, dynamicforms, dynamicstyles, webdev
Published: 2023-10-31 07:50:06

---
title: Part 3: Maximizing Angular Forms with Dynamic Custom Form Controls and Styling
published: true
description: In this article, we'll explore key strategies for optimizing dynamic forms in Angular. We demonstrate how to create modular custom form controls, implement the ControlValueAccessor interface for seamless integration, and apply runtime styling for a polished user experience. Practical examples and code snippets guide you through the process, improving form efficiency and user-friendliness. Whether you're a novice or seasoned Angular developer, this article empowers you to enhance both the developer and user experience with your dynamic forms.
tags: Angular, DynamicForms, DynamicStyles, webdevelopment
cover_image: https://dev-to-uploads.s3.amazonaws.com/uploads/articles/b96r7a8vpngz6zvfph2c.jpg
# Use a ratio of 100:42 for best results.
# published_at: 2023-10-17 18:02 +0000
---

## Introduction

In the third part of our ongoing series on dynamic forms in Angular, we'll finalize our exploration, building on the foundation laid in [Part 2: Custom Validation, Enhanced Interface, Error Handling, and Dynamic Data Binding
](https://stackblitz.com/edit/stackblitz-starters-vtb6vq?file=src%2Fmain.ts). In this article, we'll delve into how to `isolate input and dropdown components into separate custom form controls`, implement the `ControlValueAccessor` interface, and dynamically `manage styles and classes` for these custom form controls.

## Code Example
Find a live code example on StackBlitz [here](https://stackblitz.com/edit/stackblitz-starters-vtb6vq?file=src%2Fmain.ts). Feel free to explore the code and experiment with dynamic forms yourself!

Let's dive in! 🚀


### Isolating Input and Dropdown Components

In our pursuit of enhancing modularity and reusability in dynamic forms, we will establish two distinct components:

- `app-form-input`: A component designed to encapsulate input form field.
- `app-form-dropdown`: A component intended for encapsulating dropdown form field.

Our primary objective is to convert the input element into a custom form control by leveraging the `ControlValueAccessor` interface. Here's an example of how to implement the `app-custom-input` component:


```html
<!-- custom-input.component.html -->
<input
  type="text"
  [value]="value"
  (keyup)="onValueChange($event)"
  (blur)="onTouched()"
/>
```

```typescript
// custom-input.component.ts
import { ChangeDetectionStrategy, Component } from "@angular/core";
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from "@angular/forms";

@Component({
  selector: "app-custom-input",
  templateUrl: "./custom-input.component.html",
  styleUrls: ["./custom-input.component.scss"],
  standalone: true,
  providers: [
    {
      provide: NG_VALUE_ACCESSOR,
      useExisting: CustomInputComponent,
      multi: true,
    },
  ],
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class CustomInputComponent implements ControlValueAccessor {
    value: any = ""; // This is the value of the custom input
    onChange: any = (value: any) => {};
    onTouched: any = () => {};

// This method is called when you want to update the custom input's value
// from an external source. It synchronizes the internal state with the
// provided 'value'.
    writeValue(value: any): void {
      this.value = value;
    }

    // This method is called when the value of the custom input changes
    registerOnChange(fn: any): void {
      this.onChange = fn;
    }

    // This method is called when the custom input is touched
    registerOnTouched(fn: any): void {
      this.onTouched = fn;
    }

    // These methods are required by the ControlValueAccessor interface
    markAsTouched(): void {
      this.onTouched();
    }

    // This method is called when the value of the custom input changes
    onValueChange(event: any) {
      this.value = event.target.value; // Update the value of the custom input
      this.onChange(this.value); // This method call will bind the value of the custom input to the form control
      this.markAsTouched(); // This method call will mark the custom input as touched
    }
}
```

These custom form controls need to implement the **`writeValue`**, **`registerOnChange`**, and **`registerOnTouched`** methods as mandated by the **`ControlValueAccessor`** interface. These methods ensure seamless integration with the Angular Reactive Form, supporting value updates, validations, and state changes.

### Moving Input and Dropdown Components

With our custom form control components in place, we can now migrate the input and dropdown components from the app-form to these new custom components:

```html
<!-- dynamic-form-field.component.html -->
<ng-container [formGroup]="formControlValueAccessor">
  <app-custom-input formControlName="customInputValue" />
</ng-container>
```

### Using Custom Form Controls in Dynamic Forms

Having encapsulated each component within its own form control component, they are now ready for use in the dynamic form. These custom form controls can be effortlessly incorporated into the **`dynamic-form-field`** template:

```html
<!-- dynamic-form-field.component.html -->
<div class="form-item-container">
  <ng-container *ngSwitchCase="'text'">
    <app-custom-input
      type="text"
      class="form-control"
      [formItem]="formItem"
      formControlName="{{ formItem.id }}"
    />
    <mat-error>
      <app-error-message [formItem]="formItem" />
    </mat-error>
  </ng-container>

  <ng-container *ngSwitchCase="'select'">
    <app-custom-dropdown
      class="form-control"
      [formItem]="formItem"
      [formControl]="getFormControl(formItem)"
      formControlName="{{ formItem.id }}"
    />
    <mat-error>
      <app-error-message [formItem]="formItem" />
    </mat-error>
  </ng-container>
</div>
```

### Managing Styles and Classes for Dynamic Custom Form Controls

One of the challenges we encounter after integrating custom form fields is dynamically handling styles and classes for these components. Since the components are dynamic and defined in the configuration, their styling cannot be pre-defined. Instead, we can pass styles and classes through the configuration, ensuring that class names align between the configuration and CSS files.

For instance, to apply a custom style to the "email" field, you can define these styles:

```typescript
// movies.config.ts
{
  id: 'email',
  label: 'Email',
  type: 'text',
  validators: [
    // Validation rules here
  ],
  classes: ['email-field-style'], // Pass dynamic classes here
}
```
The 'email-field-style' will be applied to the email form field at runtime. 

In the HTML template, you can apply dynamic styles like this:

```html
<!-- custom-input.component.html -->
<input
  [ngClass]="formItem.styles" <!-- Pass dynamic styles here -->
  matInput
  type="text"
  class="form-control"
  [value]="value"
  (keyup)="onValueChange($event)"
  (blur)="onTouched()"
/>
```

By passing all the dynamic styles through the configuration then the dynamic styles will be applied to the dynamic form control.

In the SCSS file, define the styling for the **"email-field-style"** class. This approach allows you to attach custom classes and styles to the dynamic form controls without causing unintended side effects.

By following these steps, you can isolate input and dropdown components, create custom form controls, and manage dynamic styles and classes effectively, enhancing the flexibility and reusability of your dynamic forms in Angular.

```scss
// global_styles.scss
.email-field-style.ng-touched.ng-invalid {
  #email {
    .mdc-text-field {
      border: 2px solid orange;
    }
  }
}

```

### Summary

In this third part of our Angular dynamic forms series, 🚀 we focus on maximizing modularity, reusability, and dynamic styling. We demonstrate how to `isolate input and dropdown components into separate custom form controls`, `implement the ControlValueAccessor interface` for seamless integration, and manage 🎨 `dynamic styles and classes`. This approach enhances form flexibility and reusability, allowing you to create more dynamic and user-friendly Angular forms. 🛠️