0

I am setting up a reusable text input that could be used with reactive forms.

I am getting the following error when i add it to the declaration array of the app module and issue ng serve.

/ Generating browser application bundles (phase: building)...C:\SPA\node_modules\typescript\lib\typescript.js:19487
        return text.replace(/{(\d+)}/g, function (_match, index) { return "" + ts.Debug.checkDefined(args[+index + baseIndex]); });
                                                                                        ^

Error: Debug Failure.
    at C:\SPA\node_modules\typescript\lib\typescript.js:19487:89
    at String.replace (<anonymous>)
    at formatStringFromArgs (C:\SPA\node_modules\typescript\lib\typescript.js:19487:21)
    at Object.createDetachedDiagnostic (C:\SPA\node_modules\typescript\lib\typescript.js:19503:20)
    at parseErrorAtPosition (C:\SPA\node_modules\typescript\lib\typescript.js:30898:42)
    at parseErrorAt (C:\SPA\node_modules\typescript\lib\typescript.js:30905:13)
    at parseErrorAtCurrentToken (C:\SPA\node_modules\typescript\lib\typescript.js:30892:13)
    at parseErrorForInvalidName (C:\SPA\node_modules\typescript\lib\typescript.js:31130:17)
    at parseErrorForMissingSemicolonAfter (C:\SPA\node_modules\typescript\lib\typescript.js:31102:21)
    at parseExpressionOrLabeledStatement (C:\SPA\node_modules\typescript\lib\typescript.js:34992:21) 

My Environment

Angular CLI: 13.0.2
Node: 16.13.0
Package Manager: npm 8.1.3
OS: win32 x64

Angular:
...

Package                      Version
------------------------------------------------------
@angular-devkit/architect    0.1300.2 (cli-only)
@angular-devkit/core         13.0.2 (cli-only)
@angular-devkit/schematics   13.0.2 (cli-only)
@schematics/angular          13.0.2 (cli-only)

Here is the code

text-input.component.ts

import { Component, Input, Self } from '@angular/core';
import { ControlValueAccessor, NgControl } from '@angular/forms';

@Component({
  selector: 'app-text-input',
  templateUrl: './text-input.component.html',
  styleUrls: ['./text-input.component.css']
})
export class TextInputComponent implements ControlValueAccessor {
  
  @Input() label: string = '';
  @Input() labelMustMatch: string = '';
  @Input() placeHolder: string = '';
  @Input() type: string = 'text';

  constructor(@Self() public ngControl: NgControl) { 
    this.ngControl.valueAccessor = this;
  }

  writeValue(obj: any): void {
    
  }

  registerOnChange(fn: any): void {
    
  }

  registerOnTouched(fn: any): void {
  
  }

  setDisabledState?(isDisabled: boolean): void {}
}

text-input.component.html

<input 
    [class.is-invalid]="ngControl.invalid && ngControl.touched && ngControl.dirty"
    type={{ type }} 
    class="form-control" 
    [formControl]="$any(ngControl.control)"  
    placeholder={{ placeHolder }}
>
<!--required-->
<div class="invalid-feedback" *ngIf="ngControl.control.errors?.required">
    {{label}} is required
</div>
<!--minlength-->
<div class="invalid-feedback" *ngIf="ngControl.control.errors?.minlength">
    {{label}} must be minimum {{ngControl.control.errors.minlength['requiredLength']}} characters
</div>
<!--maxlength-->
<div class="invalid-feedback" *ngIf="ngControl.control.errors?.maxlength">
    {{label}} must be maximum {{ngControl.control.errors.maxlength['requiredLength']}} characters
</div>
<!--onlyChar-->
<div class="invalid-feedback" *ngIf="ngControl.control.errors.onlyChar">
    {{label}} must be only characters
</div>
<!--onlyCharWithSpace-->
<div class="invalid-feedback" *ngIf="ngControl.control.errors.onlyCharWithSpace">
    {{label}} must be only characters and space
</div>
<!--mustMatch-->
<div class="invalid-feedback" *ngIf="ngControl.control.errors.mustMatch">
    {{labelMustMatch}} do not match
</div>
<!--passwordStrength-->
<div class="invalid-feedback" *ngIf="ngControl.control.errors.passwordStrength">
    {{label}} must have an upper case, lower case and a number
</div>

and then using it inside the parent

<app-text-input [formControl]="registerForm.controls['userName']" [label]="'User name'" [placeHolder]="'user name'"></app-text-input>

How can i fix the error?

1 Answer 1

1

I think you may have a typo in these lines:

type={{ type }}
placeholder={{ placeHolder }}

The interpolated values should be wrapped in " quotes:

type="{{ type }}"
placeholder="{{ placeHolder }}"

You may also need to add optional chaining ? to control errors, like following:

*ngIf="ngControl.control.errors?.mustMatch"

Full example:

    <input 
      [class.is-invalid]="ngControl.invalid && ngControl.touched && ngControl.dirty"
      type="{{ type }}"
      class="form-control" 
      [formControl]="$any(ngControl.control)"  
      placeholder="{{ placeHolder }}"
    >
    <!--required-->
    <div class="invalid-feedback" *ngIf="ngControl.control.errors?.required">
      {{label}} is required
    </div>
    <!--minlength-->
    <div class="invalid-feedback" *ngIf="ngControl.control.errors?.minlength">
      {{label}} must be minimum {{ngControl.control.errors.minlength['requiredLength']}} characters
    </div>
    <!--maxlength-->
    <div class="invalid-feedback" *ngIf="ngControl.control.errors?.maxlength">
      {{label}} must be maximum {{ngControl.control.errors.maxlength['requiredLength']}} characters
    </div>
    <!--onlyChar-->
    <div class="invalid-feedback" *ngIf="ngControl.control.errors?.onlyChar">
      {{label}} must be only characters
    </div>
    <!--onlyCharWithSpace-->
    <div class="invalid-feedback" *ngIf="ngControl.control.errors?.onlyCharWithSpace">
      {{label}} must be only characters and space
    </div>
    <!--mustMatch-->
    <div class="invalid-feedback" *ngIf="ngControl.control.errors?.mustMatch">
      {{labelMustMatch}} do not match
    </div>
    <!--passwordStrength-->
    <div class="invalid-feedback" *ngIf="ngControl.control.errors?.passwordStrength">
      {{label}} must have an upper case, lower case and a number
    </div>
Sign up to request clarification or add additional context in comments.

4 Comments

Cannot use ngControl.control.errors?.required or get Property 'required' comes from an index signature, so it must be accessed with ['required']. When i use ngControl.control.errors['required'] then i get into object possibly null error. How can i get over this one?
I think you can use optional chaining on errors as well - ngControl.control.errors?.['required'].
This worked *ngIf="ngControl.control?.errors!['required']". See use of !
Here " is not needed for the interpolated values. May be a good practice though

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.