This article is about fixing Forms: State that setErrors() will make status === INVALID regardless of value passed for key in Angular
  • 25-Jan-2023
Lightrun Team
Author Lightrun Team
Share
This article is about fixing Forms: State that setErrors() will make status === INVALID regardless of value passed for key in Angular

Forms: State that setErrors() will make status === INVALID regardless of value passed for key in Angular

Lightrun Team
Lightrun Team
25-Jan-2023

Explanation of the problem

The current behavior of the setErrors example for AbstractControl in Angular’s documentation is that it shows passing true for the key. However, the issue is that the control’s status will always be set to INVALID, regardless of the value of the key or even if an empty object is passed to the setErrors function. This can lead to confusion when trying to clear errors in code, particularly when doing integration (template) testing, where the goal is to set an error, check the template, and then clear the error and check that any alerts have gone away.

Steps to reproduce:

The following code block illustrates the problem:

const login = new FormControl("someLogin");
login.setErrors({
  "notUnique": true
});

expect(login.valid).toEqual(false);
expect(login.errors).toEqual({"notUnique": true});

login.setErrors({"notUnique": false});
expect(login.valid).toEqual(true); //will still be INVALID since the check: if(this.errors) will return TRUE

Expected behavior:

The documentation should be updated to explicitly state how to clear errors in code. This can be done by setting a new valid value or by passing null to the control.setErrors() function. Alternatively, in the _calculateStatus() function, the control’s status should only be set to INVALID if at least one key in the errors object is set to true.

The motivation for this change is to provide a clear and accurate explanation of how to clear errors in code, particularly when doing integration (template) testing, in order to check that any alerts have gone away.

Troubleshooting with the Lightrun Developer Observability Platform

Getting a sense of what’s actually happening inside a live application is a frustrating experience, one that relies mostly on querying and observing whatever logs were written during development.
Lightrun is a Developer Observability Platform, allowing developers to add telemetry to live applications in real-time, on-demand, and right from the IDE.

  • Instantly add logs to, set metrics in, and take snapshots of live applications
  • Insights delivered straight to your IDE or CLI
  • Works where you do: dev, QA, staging, CI/CD, and production

Start for free today

Problem solution for Forms: State that setErrors() will make status === INVALID regardless of value passed for key in Angular

The issue at hand is the need to selectively remove errors from form controls in Angular, rather than having to clear all errors at once. This is particularly relevant when working with custom errors that are set on specific inputs, as these errors may need to be removed independently of other errors that may have been added by other validators.

One solution to this problem is to create utility methods that can be used to add or remove errors from a form control. The first answer provided a sample implementation of these methods in the form of removeErrors and addErrors which can be used to selectively remove or add errors to a form control. The removeErrors method takes in an array of keys and an AbstractControl object. It checks if the control and keys are valid, if they are it then reduces the errors by deleting the key from the errors object and sets the remaining errors to the control. If there are no errors left, it sets the errors to null.

public static removeErrors(keys: string[], control: AbstractControl) {
    if (!control || !keys || keys.length === 0) {
      return;
    }

    const remainingErrors = keys.reduce((errors, key) => {
      delete errors[key];
      return errors;
    }, { ...control.errors });

    control.setErrors(remainingErrors);

    if (Object.keys(control.errors || {}).length === 0) {
      control.setErrors(null);
    }
  }

The addErrors method takes in an object of errors and an AbstractControl object, it checks if the control and errors are valid, if they are it then sets the errors to the control.

public static addErrors(errors: { [key: string]: any }, control: AbstractControl) {
    if (!control || !errors) {
      return;
    }

    control.setErrors({ ...control.errors, ...errors });
  }

In conclusion, the proposed solution is to create utility methods that can be used to selectively remove or add errors to form controls in Angular. This allows for more fine-grained control over the errors displayed on a form and is particularly useful when working with custom errors that need to be removed independently of other errors that may have been added by other validators.

Other popular problems with Angular

Problem:

One of the most common problems with Angular is change detection performance issues. When an application becomes large and complex, it can become slow and unresponsive due to the way change detection works in Angular. The framework checks for changes in the component tree by comparing the current and previous values of all properties in all components. This can lead to poor performance if there are many complex bindings or if change detection is triggered too frequently.

Solution:

One solution to this problem is to use the OnPush change detection strategy. This strategy only checks for changes in a component when an input property value changes or an event is emitted by the component. By using OnPush, developers can reduce the number of checks performed by the change detection mechanism, resulting in improved performance. Additionally, developers can use the ChangeDetectorRef to manually trigger change detection for specific parts of the application, rather than checking the entire application.

import { Component, ChangeDetectionStrategy } from '@angular/core';

@Component({
  selector: 'app-my-component',
  templateUrl: './my-component.component.html',
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class MyComponent {
  ...
}

Problem:

Another popular problem with Angular is dealing with complex nested forms. When a form becomes large and complex, it can become difficult to manage the form’s state, validation, and error handling. This can lead to a lot of boilerplate code, making it hard to read and maintain.

Solution:

One solution to this problem is to use the FormBuilder and FormGroup classes, which provide a way to create nested forms in a more organized and reusable way. FormBuilder allows developers to create a form group and its controls in a single line of code, while FormGroup allows developers to manage the state, validation

A brief introduction to Angular

Angular is a JavaScript framework for building web applications. It is maintained by Google and is built on top of TypeScript, which is a super set of JavaScript that adds optional static typing, classes and interfaces. Angular uses a component-based architecture, which allows developers to build applications as a collection of reusable, self-contained components. Each component represents a specific view or piece of functionality, and is responsible for its own data and behavior.

Angular also provides powerful features for building dynamic web applications, such as two-way data binding, dependency injection, and a powerful template language. The two-way data binding feature allows developers to synchronize the view and the model, making it easy to update the view when the model changes, and vice versa. The dependency injection feature allows developers to easily manage the dependencies between components, making it easy to test and maintain the application. The template language provides a way to declaratively describe the structure and layout of the view, making it easy to create complex and dynamic views with minimal code.

Most popular use cases for Angular

 

  1. Angular can be used for building dynamic, client-side web applications. It provides a powerful set of features that make it easy to create complex and interactive user interfaces, such as two-way data binding, dependency injection, and a powerful template language. Angular’s component-based architecture allows developers to build applications as a collection of reusable, self-contained components, making it easy to maintain and test the application.
import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  template: `<h1>{{ title }}</h1>`
})
export class AppComponent {
  title = 'My Angular App';
}
  1. Angular can be used for building progressive web applications (PWA). PWAs are web applications that can be installed on a user’s device, and can work offline and be launched from the user’s home screen like a native app. Angular provides a powerful set of tools for building PWAs, such as the Angular Service Worker, which allows developers to cache application resources for offline use, and the Angular CLI, which provides a set of commands for generating a PWA-ready application.
  2. Angular can be used for building mobile apps using Apache Cordova or NativeScript. Apache Cordova allows developers to build cross-platform mobile apps using web technologies such as HTML, CSS, and JavaScript, while NativeScript allows developers to build truly native mobile apps using Angular and TypeScript. Both frameworks provide a set of plugins that allow developers to access native features such as the camera, GPS, and other device features.
Share

It’s Really not that Complicated.

You can actually understand what’s going on inside your live applications.

Try Lightrun’s Playground

Lets Talk!

Looking for more information about Lightrun and debugging?
We’d love to hear from you!
Drop us a line and we’ll get back to you shortly.

By submitting this form, I agree to Lightrun’s Privacy Policy and Terms of Use.