question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Ability to set a custom message while working with `Validators`

See original GitHub issue

Which @angular/* package(s) are relevant/related to the feature request?

forms

Description

It is really intimating and obvious that in most cases we need to show custom messages to the user but IDK why we cannot specify the error message in the component’s class and we have to deal with it in a painful way in templates. Another thing is that this stackoverflow Q&A shows is that I am not alone 😄 .

Proposed solution

IMO it would be more readily to specify error message in the component’s class and then use a common component to show error messages as it is described here

So in login.component.ts we have:

@Component({
  selector: 'app-login',
  templateUrl: './login.component.html',
  styleUrls: ['./login.component.css'],
})
export class AComponent {
  public loginForm: FormGroup;
  public passwordSpecialChar = '!@#$&*';
  public passwordShouldContainsSpecialChar = /(?=.*[!@#$&*])/;
  public passwordShouldContainsOneLowercaseLetter = /(?=.*[a-z])/;
  public passwordShouldContainsOneCapitalLetter = /(?=.*[A-Z])/;
  public passwordShouldContainsOneDigit = /(?=.*[0-9])/;
  constructor(private formBuilder: FormBuilder) {}

  ngOnInit(): void {
    this.loginForm = this.formBuilder.group({
      username: [
        '',
        Validators.compose([
          Validators.required({ customeMessage: 'Please enter username' }),
          Validators.minLength(6, { customeMessage: 'Username should be at least 6 character' }),
          Validators.maxLength(320, { customeMessage: 'Username cannot be more that 320 character' }),
          Validators.pattern(/[\w_-\d]/, { customeMessage: 'Username can only contains alphanumeric, hyphens, and dashes' }),
        ]),
      ],
      password: [
        '',
        Validators.compose([
          Validators.minLength(8, { customeMessage: 'c message 1' }),
          Validators.required({ customeMessage: 'c message 2' }),
          Validators.pattern(this.passwordShouldContainsSpecialChar, { customeMessage: 'c message 3' }),
          Validators.pattern(
            this.passwordShouldContainsOneLowercaseLetter,
            { customeMessage: 'c message 4' }
          ),
          Validators.pattern(
            this.passwordShouldContainsOneCapitalLetter,
            { customeMessage: 'c message 5' }
          ),
          Validators.pattern(this.passwordShouldContainsOneDigit, { customeMessage: 'c message 6' }),
        ]),
      ],
    });
  }
}

and in the login.component.html we have:

<div>
  <form [formGroup]="loginForm" (ngSubmit)="login(loginForm.value)">
    <div>
      <div>
        <label for="username">username</label>
        <span
          class="text-danger"
          *ngIf="loginForm.get('username').hasError('required')"
        >
          *
        </span>
      </div>
      <div>
        <!-- formControlName Syncs FormControl in an existing FormGroup instance to a form control element by name. -->
        <input
          placeholder="Enter your username"
          type="text"
          name="username"
          id="username"
          formControlName="username"
        />
      </div>
      <div
        *ngIf="
          loginForm.get('username').invalid &&
          loginForm.get('username').errors &&
          (loginForm.get('username').dirty ||
            loginForm.get('username').touched)
        "
      >
        <app-validation-errors
          [errors]="loginForm.get('username').errors"
        ></app-validation-errors>
      </div>
    </div>
    <div>
      <div>
        <label for="password">password</label>
        <span
          class="text-danger"
          *ngIf="loginForm.get('password').hasError('required')"
        >
          *
        </span>
      </div>
      <div>
        <input
          placeholder="Enter your Password"
          type="password"
          formControlName="password"
          name="password"
          id="password"
        />
      </div>
      <div
        *ngIf="
          loginForm.get('password').invalid &&
          (loginForm.get('password').touched ||
            loginForm.get('password').dirty)
        "
      >
        <app-validation-errors
          [errors]="loginForm.get('password').errors"
        ></app-validation-errors>
      </div>
    </div>
    <div>
      <div>
        <button
          [dissabled]="!loginForm.valid"
          type="submit"
          value="Login"
        ></button>
      </div>
      <div>Form Status: {{ loginForm.status }}</div>
    </div>
  </form>
</div>

and in the validation-errors.component.html I could state error messages vividly

<ng-container
  class="text-danger"
  *ngIf="errors && errors['required']"
>
  {{
    errors['required'].customMessage ? errors['required'].customMessage : 'This field is required'
  }}
</ng-container>

<!-- The same thing for the rest of it -->

Why am I motivated and think this is a unquestionable need?

I used to be a backend developer and I really appreciate class-validator. Now I came to learn Angular but I really feel that this is a dire need that has been forgotten or maybe it does not felt at all. BTW this is just an opinion.

Alternatives considered

Or at least we should have the power to change the default error message. In the login.component.ts:

/* ... */
Validators.required({ message: 'Please enter username' }),
/* ... */

Issue Analytics

  • State:closed
  • Created a year ago
  • Reactions:7
  • Comments:9 (5 by maintainers)

github_iconTop GitHub Comments

5reactions
jnizetcommented, Jun 17, 2022

There are libraries doing somewhat what you want (like one I wrote: https://ngx-valdemort.ninja-squad.com/#/, even if custom messages are still specified in the template).

But even what you want can be done quite easily: you simply need to wrap the standard validators into your owns, and store the custom message in the error you return:

function required(customMessage: string): ValidatorFn {
  return ctrl => {
    const error = Validators.required(ctrl);
    return error ? { required: { customMessage } } : null;
  };
}
0reactions
angular-automatic-lock-bot[bot]commented, Oct 23, 2022

This issue has been automatically locked due to inactivity. Please file a new issue if you are encountering a similar or related problem.

Read more about our automatic conversation locking policy.

This action has been performed automatically by a bot.

Read more comments on GitHub >

github_iconTop Results From Across the Web

HTML5 form required attribute. Set custom validation message?
In my case I want to check that the value is a number before posting but I can't use the type="number" attribute (for...
Read more >
Display custom validation messages for the required fields
Solved: Hi, How to show custom validation message for required field (sharepoint).By default for required fields the validation message will be:
Read more >
Angular Custom Form Validators: Complete Guide
All about custom form validators, including synchronous and asynchronous, field-level, form-level, for both template-driven and reactive ...
Read more >
Angular Reactive forms Custom Validators ... - YouTube
Angular Reactive forms Custom Validators & Custom Validation messages | Angular | Learn Smart Coding · Key moments. View all · Key moments ......
Read more >
Add Custom Error Message feature to Regular Expression ...
When working with workflows, it is possible to create validators based on Regular Expressions. However, unlike other validators such as the Field Required ......
Read more >

github_iconTop Related Medium Post

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found