Angular Form Validations - input values must not match the initial values

These are my current reactive form validations:

  ngOnInit(): void {
    this.userForm = this.formBuilder.group({
      status: {checked: this.selectedUser.status == 1},
      username: [this.selectedUser.username, [Validators.required, Validators.minLength(LlqaConstants.USERNAME_MIN_LENGTH)]],
      realname: [this.selectedUser.realname, [Validators.required, Validators.minLength(LlqaConstants.REALNAME_MIN_LENGTH)]],
      password: ['', this.selectedUser.passhash.length > 0 ? [Validators.required, Validators.minLength(LlqaConstants.PASSWORD_MIN_LENGTH)] : null],
      usercomment: [this.selectedUser.comment]
    });
  }

I want to make the submit button enabled when at least one input value is different from the initial value. The method I tried is:

disableSaveButton(): boolean {
  return !this.userform.dirty || this.userForm.invalid;
}

The issue with the dirty property is that it becomes true as soon as any change is made, even if the new value is the same as the initial one. Is there a way to check only for values that have actually changed, rather than comparing all userForm.value with this.selectedUser.someValue?

Answer №1

I developed a unique validator to tackle this particular issue.

The custom validator I implemented is shown below:

export function customValidationForValues(values: { name: string, initValue: string | number | boolean }[]): ValidatorFn {
  return (form: FormControl): { [key: string]: any } => {
    let areValuesSame = true;

    for (let val of values) {
      if (form.value[val.name] != val.initValue) {
        areValuesSame = false;
        break;
      }
    }

    return areValuesSame ? {'sameValuesError': {values: values}} : null;
  };
}

Here's how I utilized the custom validator in my code:

this.customForm = this.formBuilder.group({
  status: this.selectedItem.status == 1,
  itemName: [this.selectedItem.itemName, [Validators.required, Validators.minLength(Constants.ITEM_NAME_MIN_LENGTH)]],
  description: [this.selectedItem.description, [Validators.required, Validators.minLength(Constants.DESCRIPTION_MIN_LENGTH)]],
  quantity: ['', [Validators.minLength(Constants.QUANTITY_MIN_LENGTH)]],
  comments: this.selectedItem.comments == null ? "" : this.selectedItem.comments
});

this.customForm.setValidators(customValidationForValues([{
  name: "status",
  initValue: this.selectedItem.status == 1
}, {
  name: "itemName",
  initValue: this.selectedItem.itemName
}, {
  name: "description",
  initValue: this.selectedItem.description
}, {
  name: "quantity",
  initValue: ""
}, {
  name: "comments",
  initValue: this.selectedItem.comments == null ? "" : this.selectedItem.comments
}]));
this.customForm.updateValueAndValidity();

Answer №2

One way to optimize performance is by storing the initial value of the form object in a cache as soon as it is set. Then, you can modify your disableSaveButton function to compare the two values for equality.

Here's an example implementation:

export class CustomComponent {
    initialValue: any;

    constructor(private fb: FormBuilder) {
        this.form = fb.group({...});
        this.initialValue = this.form.value;
    }

    disableSaveButton() {
        return JSON.stringify(this.initialValue) === JSON.stringify(this.form.value);
    }
}

This updated method will verify whether the current form value matches the original value stored in cache.

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

Unpacking intricate function arguments in TypeScript

I am working with the following model classes: export class Book { public name: string; public id: string; ... } export class Author { public firstName: string; public lastName: string; ... } The my-component triggers an event t ...

When the page hosted on Vercel is reloaded, `getStaticProps` does not function as expected

I'm currently working on a nextjs project and running into an issue where one of the pages returns a 404 error when it's reloaded. Within the page directory, I am using getStaticProps. pages - blogs.tsx - blog/[slug].tsx - index.tsx ...

Using Angular's routerLink feature to assign a specific outlet (version 5.0.2)

Despite reading numerous posts on this problem, none of the solutions seem to work for me. I am working with one app module, one routing module, and no additional modules. The issue I'm facing is that... Standard routes can be linked from any compo ...

Can you explain the TypeScript type for the queryKey in React Query?

Currently utilizing react query in conjunction with typescript. What should be the type of arguments passed to the function? export const useIsTokenValid = () => { const { data: token } = useQuery<string | null>(['token'], getToken, { r ...

Angular: The fetched data from the API is coming back as undefined

I am trying to use the Highcharts module in Angular to build a chart. The data object needed for the chart is provided by an API, and this is the structure of the object: { "success": true, "activity": [ { &q ...

Harvesting Angular information using Selenium

Here is some HTML code that can be extracted using a Selenium driver: <td colspan="2"><strong>Owner</strong> <div ng-class="{'owner-overflow' : property.ownersInfo.length > 4}"> ...

Using the css function within styled-components

Struggling with implementing the media templates example from the documentation and figuring out how to type the arguments for the css function in plain JS: const sizes = { desktop: 992 } const media = Object.keys(sizes).reduce((acc, label) => { ...

Pass data that has been asynchronously resolved from the parent component to the child component using props in Vue

Main component: <template> <div> <Nav :data="data" /> </div> </template> <script lang="ts"> // ... imports removed for clarity @Component({ components: { Nav: () => import('@/components/Nav.vue&ap ...

Error: Component fails to compile when imported via a module in TestBed

Struggling to write unit tests for a component that includes another component tag in its HTML. <bm-panel [title]="title" [panelType]="panelType" [icon]="icon" class="bm-assignment-form-panel"> <div *ngIf="isLoading" class="bm-loader"> ...

Exclude a select few rows in MatSort, rather than excluding entire columns

When the user clicks on the Date column for sorting, it is required to exclude empty rows from the sorting. Empty rows are present due to the application of ngIf on those particular rows. The requirement states that rows with empty column values should eit ...

Sequelize: Query results do not have defined instance methods and properties

The Sequelize version is 6.6.2 Mysql2 version: 2.2.5 I have constructed my Model in the following manner and defined methods as shown: interface IUserAttributes { user_id: number; logon_name: string; user_password: string; full_name: string; di ...

What is the best way to pass a generic interface to the zustand create function in a TypeScript environment

Having trouble figuring out the right syntax to pass a generic interface when calling a function that accepts a generic type. My goal is to use: const data = itemStore<T>(state => state.data) import { create } from "zustand"; interface ...

What is the process for importing a JSON file into a TypeScript script?

Currently, I am utilizing TypeScript in combination with RequireJS. In general, the AMD modules are being generated flawlessly. However, I have encountered a roadblock when it comes to loading JSON or any other type of text through RequireJS. define(["jso ...

Ways to identify a modification in ag-grid when there is an update in my row data while transitioning from one component to another

I am currently working on a project using angular6 implementing ag-grid to display data from an angular dialog box. With multiple teams contributing, each creating their own components, I have encountered a unique situation that I am struggling to resolv ...

I'm having trouble retrieving the object value from a different function within my Typescript and Express application

Currently I am experimenting with utilizing typescript alongside express for my application development. I have created a function that I intend to utilize in various sections of my codebase. Upon invoking the function, I am able to observe the values thro ...

"Error encountered: 'Callable function cannot be invoked on Mongoose model

In my Nest JS service, the code structure is as follows: import { Injectable } from '@nestjs/common'; import { Model } from 'mongoose'; import { InjectModel } from '@nestjs/mongoose'; import { Collection } from './inter ...

Exploring JSON data in Angular

I am currently working with a Json file that contains two different objects: readers and books. Here is an example of the structure: { "users": [{ "id": 1, "username": "peterB", }, { "id": 2, "username": "MaryC" ...

What could be causing the 404 error when trying to make a get-request to fetch a list of all users?

Having trouble retrieving a list of users using my endpoint, as it keeps returning a 404 error. I have set up a model, controller, router, and index file for the user in my application. Below is the User.ts model: import { Schema } from 'mongoose&apo ...

Checking for the input value using ngIf

Users can input information into a field, and based on what they enter, the element below will display their input. <label>message</label> <input type="text" name="name" [(ngModel)]="person.message"class="form-control"> <label cla ...

The main module's postinstall process is initiated before the sub-module's postinstall process

Update: I am seeking guidance on how to install a module from GitHub instead of npm. That's the main query. In case you're wondering why: I'm currently working on some confidential projects and prefer not to publish the code. As a result, ...