Access pass necessary for customizing Angular components

I have developed a unique custom phone number component

I am looking to incorporate the required flag for validation purposes

Below is the HTML structure of the custom phone number component:

  <form #phoneForm="ngForm" novalidate name="PhoneForm">
    <div class="form-row">
        <div class="form-group col-md-3">
           <p-dropdown
              #phoneCodeInput = ngModel
              [disabled]="!countrycodes.length"
              [options]="countrycodes"
              autoWidth="false"
              [(ngModel)]="phoneCode"
              (ngModelChange)="onNumberChange()"
              [style]="{ width: '100%', height: '100%'}"
              name="countryCodes"
              [autoWidth]="true"
            ></p-dropdown>
        </div>
        <div class="form-group col-md-9">
        <input
            [readonly] = "isReadOnly"
            #phoneNumberInput = ngModel
            number-directive
            class="form-control"
            placeholder="Enter phone number"
            required
            [(ngModel)]="phoneNumber"
            (ngModelChange)="onNumberChange()"
            type="text"
            name="name"
            maxlength="11"
        />
        </div>
    </div>
    <validation-messages [formCtrl]="phoneNumberInput"></validation-messages>
  </form>

Here is the typescript code for the phone number component, which includes the use of Input parameter for validation:

import { AppComponentBase } from '@shared/common/app-component-base';
import {
    Component,
    OnInit,
    Injector,
    AfterContentChecked,
    ViewChild,
    forwardRef,
    Input,
} from '@angular/core';
import * as lookup from 'country-telephone-data';
import { SelectItem } from 'primeng/api';
import { ControlValueAccessor, ValidationErrors, NG_VALUE_ACCESSOR, NG_VALIDATORS } from '@angular/forms';


@Component({
    selector: 'phone-number',
    templateUrl: './phone-number.component.html',
    providers: [
        { provide: NG_VALUE_ACCESSOR, useExisting: PhoneNumberComponent, multi: true },
        {
            provide: NG_VALIDATORS,
            useExisting: forwardRef(() => PhoneNumberComponent),
            multi: true
        }
    ]
})
export class PhoneNumberComponent extends AppComponentBase
    implements OnInit, ControlValueAccessor, AfterContentChecked {
    @Input() isRequired: boolean;
    @ViewChild('phoneForm') phoneForm;
    constructor(injector: Injector) {
        super(injector);
    }
    countrycodes: SelectItem[] = [];
    phoneCode: string;
    phoneNumber: string;
    required: string | boolean;
    isFieldRequired: boolean = false;
    isReadOnly: boolean = false;

    private changed = [];
    private touched = [];

    disabled: boolean;


    ngAfterContentChecked(): void {
        this.checkValidity();
    }

    checkValidity(): void {}
    propagateChange = (_: any) => {};

    get phoneNumberResult(): string {
        const result = `${this.phoneCode ? this.phoneCode : ''} ${
            this.phoneNumber ? this.phoneNumber : ''
        }`;
        return result;
    }

    set phoneNumberResult(value: string) {
        if (this.phoneNumberResult !== value) {
            const [phoneCode, phoneNumber] = value.split(' ');
            this.phoneCode = phoneCode;
            this.phoneNumber = phoneNumber;
            this.changed.forEach(f => f(value));
        }
    }

    writeValue(obj: string): void {
            this.phoneNumberResult = obj ? obj : '+44';
    }
    registerOnChange(fn: any): void {
        this.propagateChange = fn;
    }
    registerOnTouched(fn: any): void {
        this.touched.push(fn);
    }
    setDisabledState?(isDisabled: boolean): void {
        this.disabled = isDisabled;
    }


    ngOnInit(): void {
        if (this.isRequired === true) {
            this.isFieldRequired = true;
        }
        lookup.allCountries.forEach(element => {
            this.countrycodes.push({
                label: `+${element.dialCode}`,
                value: `+${element.dialCode}`,
            });
        });
    }

    onNumberChange(): void {
        this.propagateChange(this.phoneNumberResult);
    }


    validate(): ValidationErrors {
        if (!this.phoneForm.valid) {
            return { message: 'custom error' };
        }
        return null;
    }

    registerOnValidatorChange(fn: () => void): void {
        this.checkValidity = fn;
    }
}

To simplify the usage of my component, I want to utilize just the required flag at component call. Here's an example of how I achieve that:

<phone-number required id="" name="mobile" [(ngModel)]="tenant.mobileNumber" (ngModelChange)="onMobileChanged()"></phone-number>

This allows straightforward implementation of the required functionality in the component call.

Answer №1

If you want to implement form validation in Angular, consider using the <mat-form-field> component. This allows you to easily control the required attribute and display custom error messages.

<mat-form-field>
    <input matInput placeholder="Enter Phone Number" [formControl]="phoneNumber" required>
    <mat-error *ngIf="phoneNumber.invalid">{{getErrorMessage()}}</mat-error>
</mat-form-field>

To gain a better understanding, check out this helpful link. Also, take a look at this example.

Answer №2

Have you considered using ngRequired in conjunction with the

<input ng-model="required" id="required" />
tag?

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

Retrieve an instance of the property class within a property decorator

I'm attempting to create a decorator called @Prop that will assist me in adjusting attributes for custom elements. This is the desired code: class MyCustomClass extends HtmlElement { get content() { return this.getAttribute('content&apo ...

Exploring the use of v-model in Vue3 child components

After some exploration, I recently discovered that in Vue3, the v-model functionality does not work responsively or reactively with child Component. The following code snippet showcases how the username data gets updated: <template> <div> ...

Different methods to display my view when the initial value is late

I am facing an issue with a component that manages a boolean value in its state and has a button to toggle this value. The boolean value is obtained from an object created in a parent component. The button gets rendered when the object is created, but th ...

Using JSON / jQuery: How to Handle XML Data in the Success Function of an AJAX Post Request

Greetings! I am currently performing an ajax post through a JSP. The JSON data is being sent in string format (parsed using parseJSON, then converted back to a string using JSON stringify). The post operation functions correctly. However, my query lies in ...

Steps for verifying a user's username during the registration process with express validator

In developing a back-end API for authentication/authorization using Express and Node, I have integrated MongoDB to handle data storage. To validate input requests, I have opted to utilize the express-validator library. One particular validation requiremen ...

Exploring ways to utilize Next.js (React) for formatting date and time with either Moment.js or alternate

When deciding on the best method for handling date formats in my next front-end app, should I use Moment.js or JavaScript functions? The data is sourced from the backend as the date type, and I want it to be displayed in a user-friendly format while consid ...

Exploring the Differences Between Arrays of Objects and Arrays in JavaScript

While working on a project for a client, I encountered an interesting problem. I have two arrays - one with objects and one with values. The task is to populate the array of objects with new objects for every item in the value array. To clarify, here is th ...

Unknown Parameters Issue with Vue.js Router Links

Within my Vue.js project, I am utilizing params in my navigation.vue component to pass data onto the next page for dynamic routing purposes. Below is an example of how I am using this: <router-link tag="p" :to="{name: 'Main', ...

What is the process for fading out using jQuery?

There's a javascript function that I've been working with: function hideElement(id) { var x = document.getElementById("desc_div" + id).style.display = "none"; } I'm looking to replace the display = "none" with a fadeOut effect using jQ ...

Exploring the idea of nesting Angular components with dynamic data

I am attempting to create a nested structure using multiple components in the following way. My objective is to pass user data into the user-item component without directly including the item component inside the list component. Main-App <app-user-li ...

What is the best way to convert newline characters into <br> tags within a JSON string?

In my JSON file, I am receiving the following raw string. When I console.log it, it displays perfectly. "Hello, my name is Jane, from "IStaff" company.\r\n\r\n.We are interested in your service.\r\n\r\n.Please call ...

Proper method for updating a component prop in Vue.js from within its method

Here is the code snippet for a Vue.js component: var list = Vue.component('list', { props: ['items', 'headertext', 'placeholder'], template: ` <div class="col s6"> <div class="search"> ...

The type 'AxiosResponse<IUser, any>' is not to be mistaken for an array type

I am facing a minor issue while working with axios response in my code. I have a method that fetches user profiles from an API: static async getProfileById(id: string | undefined){ const jwt = localStorage.getItem("jwt"); const response ...

What is the process for renaming a Discord channel through nodeJS and discordJS?

I'm currently developing my first Discord bot using node.js and discord.js. My objective is to provide real-time information about a Minecraft server through Discord. What I aim to achieve is to have a channel that automatically updates its name per ...

Issue: ReactJS + MaterialUI + TypeScript - Property 'component' does not exist?Possible error in ReactJS: component property is

Currently, I am designing my own custom typography. However, I have encountered an error while implementing it. I have been referring to the following documentation: https://mui.com/material-ui/api/typography/ Here is the code snippet that I am using: h ...

Transforming a base64 encoded string into a byte array

I have implemented a form where users can upload images to the page using an <input id = "fileLoader" type = "file" />. With JavaScript, I convert these uploaded images to base64 and send them to the server. On the server side, I need to decode this ...

Unable to transfer the properties of reactjs to react-chartist

How can I pass the state from the parent component "main.js" into the child component "bar.js"? //main.js import React, { Component } from 'react'; import BarChart from './Bar-chart'; class Hero extends Component { cons ...

Ways to implement a transition effect when the hover state is deactivated or no longer present

After applying a transition to the header using the hover pseudo-class, I noticed that it abruptly snaps back to its original position when the hover effect is removed. Is there a way to smoothly return the header to its original position using the same ...

Leverage the power of Fluentlenium to effortlessly upload a file using dropzone.js

Currently, I am trying to create a test for file uploading using Fluentlenium and DropZone.js (). Dropzone.js operates within a modal where users can drag and drop files or upload them traditionally. However, the test crashes as soon as the upload button ...

Getting the value from a dropdown menu and displaying it in a text area

I have 3 functions (radio, textarea, and dropdown) I was able to successfully retrieve the values of radio and textarea into the textarea. However, the drop down functionality is not working as expected. My goal is to display the selected option from the ...