Custom Angular Form Control Implementation

Greetings! I'm currently in the process of developing a collection of custom reactive form controls to make it easier for templates. So far, I've successfully created one using the ControlValueAccessor interface. The form editing functionality is working smoothly, but I'm facing difficulties in displaying error messages. Can anyone provide suggestions on how to pass and display error messages within the HTML of custom controls?

Check out my code below:

input-form.component.html

<div style="font-size: 12px">
  <mat-form-field appearance="outline">
    <mat-label>{{ label }}</mat-label>
    <input
      matInput
      [required]="required"
      [readonly]="readonly"
      [formControl]="textInputFormControl"
      (input)="change()"
    />
  </mat-form-field>
</div>

input-form.component.ts

import { Component, Input, OnChanges } from '@angular/core';
import {
  ControlValueAccessor,
  FormControl,
  NG_VALUE_ACCESSOR,
} from '@angular/forms';
import { getErrorMessage } from '../form-fields.helper';

@Component({
  selector: 'x-text-input',
  templateUrl: './text-input.component.html',
  styleUrls: ['./text-input.component.scss'],
  providers: [
    {
      provide: NG_VALUE_ACCESSOR,
      multi: true,
      useExisting: TextInputComponent,
    },
  ],
})
export class TextInputComponent implements ControlValueAccessor {
  

  public textInputFormControl = new FormControl('');
  onTouched = () => {};
  onChange: (_: string) => {};

  @Input()
  public label: string;

  @Input()
  public readonly: boolean;


  public change() {
    this.onChange(this.textInputFormControl.value);
    this.onTouched();
  }

  writeValue(value: any): void {
    this.textInputFormControl.setValue(value);
  }
  registerOnChange(fn: any): void {
    this.onChange = fn;
  }
  registerOnTouched(fn: any): void {
    this.onTouched = fn;
  }

  setDisabledState(disabled: boolean) {
    disabled
      ? this.textInputFormControl.disable({ emitEvent: false })
      : this.textInputFormControl.enable({ emitEvent: false });
  }
}

Many thanks!

Answer №1

Recently uncovered a neat feature in Angular 14:

  public ngControl: NgControl = Object.assign(inject(NgControl), {
    valueAccessor: this,
  });

In the implementation of ControlValueAccessor, you can eliminate the providers array, constructor, and even extend from this class. If formControl is not applied to the component, it will throw errors indicating that CVA methods cannot be read at runtime (due to no control being set as accessor).

Answer №2

Your unique form control does not need to be tied to reactive forms specifically. It can be independent of any form module. In addition, if you require validations, you must incorporate the Validator interface.

Take a look at this interactive StackBlitz tutorial showcasing how to accomplish this. Focus on the required-field component.

You may also want to read my comprehensive article that delves into creating a custom form control complete with validations.

UPDATE:

In response to your question in the comments, there is a helpful guide available in Material's official documentation. Although I have never personally implemented a custom control with Material, it should still be feasible to introduce NgControl without utilizing formControl, similar to what was demonstrated in the StackBlitz example.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Cultural adaptation in Angular

I have successfully created an Angular project with internationalization capabilities. However, I am now looking to implement it by culture, such as es-AR or en-NZ. Below are my configurations for Spanish and English in the angular.js file: "build": { ...

Authentication with API Tokens in Rails 5

I am currently developing an API using rails 5 and I am looking to implement token authentication for consumption with angular 2 as the frontend. After installing devise, I found that most tutorials use devise_token_auth for this purpose. Can someone clari ...

What is the process for retrieving the API configuration for my admin website to incorporate into the Signin Page?

My admin website has a configuration set up that dynamically updates changes made, including the API. However, I want to avoid hardcoding the base URL for flexibility. How can I achieve this? Please see my admin page with the config settings: https://i.st ...

Retrieve the desired destination URL in the CanActivate guard when lazily loading modules in Angular

I am facing an issue with retrieving the target URL in the canActivate guard. Even though I have set up preloadingStrategy: PreloadAllModules in RouterModule.forRoot, the url property of ActivatedRoute does not contain the path. Here are the contents of bo ...

WebSocket connection outbound from Docker container fails to establish

Running a TypeScript program on Docker that needs to open a Websocket connection to an external server can be a bit tricky. Here is the scenario: ----------------------- ------------------------------ | My Local Docker | ...

Tips for retrieving data from Angular Material Table source

It's great to see everyone doing well! I'm facing an issue with rendering data to a material table, and I can't figure out why it's not working. When I try to assign the data to the table's datasource for rendering, the information ...

Is it possible to assign an object literal to a typed variable in TypeScript? Can you also specify the typeof object literal?

Consider a scenario where you have the following type definition: type MyType = { A: number | string } If you try to assign a value like this, TypeScript will correctly flag it as an error: const myValue1: MyType = { A: 123, B: "Oh!", // This wil ...

Understanding the complexity of defining the type of a function can be challenging. If you're tasked with a complicated function, determining its type

Let's break it down: Dict is defined as { [key: string]: () => any } The desired return value is represented by X I am attempting to create a type for a function that: Takes in a dictionary Dict T Returns an X Now, X also functions as a functio ...

Unable to transfer information from the Parent component to the Child component

Can you help me solve this strange issue? I am experiencing a problem where I am passing data from a parent component to a child component using a service method that returns data as Observable<DemoModel>. The issue is that when the child component ...

Prevent clicking outside the bootstrap modal in Angular 4 from closing the modal

Just starting out with angular4 and incorporating bootstrap modal into my project. I want the modal to close when clicking outside of it. Here's the code snippet: //in html <div bsModal #noticeModal="bs-modal" class="modal fade" tabindex="-1" rol ...

The attribute 'ref' is not found in the type 'IntrinsicAttributes & PhoneInputProps & { children?: ReactNode; }'

I keep receiving the following error message: Property 'ref' does not exist on type 'IntrinsicAttributes & PhoneInputProps & { children?: ReactNode; }'. How can I resolve this issue? import React, {ForwardedRef} from 'react ...

What is the process for authenticating and sending a click conversion to Google Ads using a service account and the REST API with TypeScript?

I have attempted to authenticate using this documentation and to send conversions via REST API using this REST endpoint due to the absence of a Typescript/Javascript Client Library. However, I am encountering authentication issues. Once resolved, I aim to ...

Utilize the click functionality in Angular along with Openlayers to identify the specific layer that has been clicked

Currently, I am working on an openlayers map project and need a way to identify the layer I am clicking on. This information is crucial as I plan to retrieve specific data from geoserver regarding the clicked layer. In the past, I managed to achieve this ...

The AOT Compilation error occurs in Angular2 RC6 when trying to call the function RouterModule.forChild(ROUTES) which is not supported

Operating Environment: Windows 10, IntelliJ 2016.2, node Angular Version: 2.0.0-rc.6 Language: [all | TypeScript X.X | ES6/7 | ES5] Typescript ES6 Node (for Ahead of Time Compilation issues): node --version = Node 4.4.7, NPM 3.10.6 The AOT com ...

Adding a fresh element and removing the initial item from a collection of Objects in JavaScript

I'm working on creating an array of objects that always has a length of five. I want to push five objects initially, and once the array reaches a length of five, I need to pop the first object and push a new object onto the same array. This process sh ...

The project needs to either compile a comprehensive list of all files or adhere to an 'include' pattern

When working in VSCode, I came across this warning: https://i.sstatic.net/jvUsk.png The line of code that triggered the TypeScript warning is: import packageJson from "../package.json"; Interestingly, the project builds and lints without any issues: $ ...

Encountered a resource loading error while launching a Spring-Boot Application with an Angular 7 Frontend due to missing resources

tag, I am eager to construct a Spring-Boot-Application with an Angular frontend. Initially, I utilized the Spring-Boot-Initializer to establish a project and incorporated a RestController for /greet/world. Following that, in my src/main-folder, I initiate ...

The Bootstrap grid system classes fail to adapt when the screen size is altered

After adjusting the screen size in the browser with the Device Toolbar, I've noticed that the Bootstrap Grid System classes (col-lg-12, col-md-6, etc.) do not take effect until I refresh the page. What could be causing this issue and how can it be res ...

What steps are required to generate dist/app.js from a script file in my TypeScript project?

I am currently working on a project using node, express, and TypeScript. When I run npm run build, everything builds without any issues. However, when I attempt to run npm run start, I encounter the following error: @ruler-mobility/[email protected] /User ...

How to access the dynamic route's path in Next.js when using Server Components?

Obtaining the dynamic route path in a Next JS server component poses a challenge. This task is simple when working with client components. If you are working on src/app/[id]/page.tsx "use client"; import { usePathname } from "next/navigatio ...