Angular form validation work incorrect in template-driven form

85 views Asked by At

I have own small project for estimation of Angular functionality on GitHub https://github.com/OlPrognimak/ordermanager. There I use different approaches in development to see how it works. Although the project is created for estimation purposes ones made the real work. You can with ordermanager app create users, organisations, private persons and produce invoices. All data keeps in the database. In some cases in the project I use template-driven forms and in some case reactive forms. With validation in reactive forms i have no problems, but with template-driven, where are custom components there are some problems with validation. When iI load the page "Create new person" first time all mandatory fields marked as fields with errors and the Save button is disabled by means formRef.invalid

<p-button [disabled]="personForm.invalid" label="Save" (onClick)="savePerson($event)"></p-button>

After filling the form with correct data all validations is fulfilled correctly and the button Save is enabled for clicking. Till now all works without any problems. As if I try gain insert incorrect value into the any field then that field shows error state but the button Save still staying available and formRef.invalid is false. It looks like the back validation doesn't work. Please check my code in ordermanager app (it is free available on GitHub). In master branch I use custom validation method haveErrors() but in the branch **feature/Disable_Save_Button ** I use form property invalid (personForm.invalid). I post hier custom component with input control and component where I use this component in multiple places. For more details clone the from ordermanager project. Any helpful comments welcome and not only about the described problem but also common to implementation.

Custom component:

HTML Template

<div style ="display: table; width: 100%;">
  <div style ="display: table-row; width: 100%;">
    <div style ="display: table-cell; width: 100%;">
               <span class="p-float-label">
                    <input  class="ng-dirty p-mr-2"
                           name="{{inputName}}"
                           pInputText
                           required
                            [pattern]="inputPattern"
                           minlength="{{txtMinLength}}"
                           id="{{idComponent}}"
                           type="{{inputType}}"
                           [(ngModel)]="value"

                           #modelRef="ngModel"/>
                  <label for="{{idComponent}}">{{labelText}}</label>
               </span>
    </div>
    <div *ngIf=
           "setHasMinLengthError(modelRef.errors?.minlength !== null, modelRef.errors?.minlength)" style ="display: table-cell; width: 10%;">
        <p-message severity="error"></p-message>
    </div>
    <div *ngIf="setHasRequiredError(modelRef.errors?.required !== undefined && modelRef.errors?.required !== null, modelRef.errors?.required)" style ="display: table-cell; width: 10%;">
      <p-message severity="error"></p-message>
    </div>
    <div *ngIf="setHasPatternError(modelRef.errors?.pattern!=null, modelRef.errors?.pattern)" style ="display: table-cell; width: 10%;">
      <div *ngIf="modelRef.errors?.minlength===undefined">
        <p-message severity="error"></p-message>
      </div>
    </div>
  </div>
  <div *ngIf="modelRef.errors?.pattern" class="alert alert-danger">
    {{patternErrorText}}
  </div>
</div>

*TypeScript *

........

@Component({
  selector: 'app-validatable-input-text',
  templateUrl: './validatable-input-text.component.html',
  styleUrls: ['./validatable-input-text.component.css'],
  providers: [
    {
      provide: NG_VALUE_ACCESSOR,
      useExisting: forwardRef(() => ValidatableInputTextComponent),
      multi: true
    }
  ]
})
export class ValidatableInputTextComponent implements OnInit, ControlValueAccessor  {
  /** minimal length of text */
  @Input()  public txtMinLength = 30;
  @Input() public idComponent = '';
  @Input()  labelText = '';
  @Input() inputType = 'text';
  @Input() inputPattern: any;
  @Input() controlValue = '';
  @Input() name: any='';
  @Input() inputName: string;
  @Input() patternErrorText: string
  @Output() componentHasErrorEvent = new EventEmitter<boolean>


  onChange: (val) => {};
  onTouched: () => {};
  hasRequiredError: boolean =  false
  hasMinLengthError: boolean =  false
  hasPatternError: boolean = false

  lastEmitedValue: boolean = undefined
  disabled: boolean = false

  setHasRequiredError(val: boolean, origin: any) {
    if(this.hasRequiredError === undefined || this.hasRequiredError !==val) {
      this.hasRequiredError = val
      const emitVal = this.hasError()
      if(this.lastEmitedValue === undefined || this.lastEmitedValue !== emitVal) {
        this.lastEmitedValue = emitVal
        this.componentHasErrorEvent.emit(emitVal)
      }
    }
    return origin
  }

  setHasMinLengthError(val: boolean, origin: any) {
    if(this.hasMinLengthError === undefined || this.hasMinLengthError !==val) {
      this.hasMinLengthError = val
      const emitVal = this.hasError()
      if(this.lastEmitedValue === undefined || this.lastEmitedValue !== emitVal) {
        this.lastEmitedValue = emitVal
        this.componentHasErrorEvent.emit(emitVal)
      }
    }

    return origin;
  }

  setHasPatternError(val: boolean, origin: any) {
    if(this.hasPatternError === undefined || this.hasPatternError !==val) {
      this.hasMinLengthError = val
      const emitVal = this.hasError();
      if(this.lastEmitedValue === undefined || this.lastEmitedValue !== emitVal) {
        this.lastEmitedValue = emitVal
        this.componentHasErrorEvent.emit(emitVal)
      }
    }

    return origin;
  }

  private hasError() {
    const emitVal = (this.hasRequiredError === true ||
      this.hasMinLengthError === true ||
      this.hasPatternError === true)
    return emitVal;
  }

  constructor(private renderer: Renderer2, private elementRef: ElementRef, private cdr: ChangeDetectorRef) { }


  ngOnInit(): void {
  }

  // get accessor
  get value(): any {
    return this.controlValue;
  }

  // set accessor including call the onchange callback

  set value(v: any) {
    console.log('set value :'+v)
   // if (v !== this.controlValue) {
      this.controlValue = v;
      this.onChange(v);
      this.cdr.detectChanges()
   // }
  }

  registerOnChange(fn: any): void {
    this.onChange = fn;
  }

  registerOnTouched(fn: any): void {
    this.onTouched = fn;
  }

  setDisabledState(isDisabled: boolean): void {
    this.disabled = isDisabled
  }

  /**
   *
   */
  writeValue(value: any): void {
      this.controlValue = value;
  }

}

@NgModule(
  {
    imports: [CommonModule, MessagesModule, MessageModule, FormsModule, ToastModule, InputTextModule],
    declarations: [ValidatableInputTextComponent],
    exports: [ValidatableInputTextComponent],
    schemas: [CUSTOM_ELEMENTS_SCHEMA]
  }
)
export class ValidatableInputTextModule{

}

Usage of custom component.

HTML Template:

<div *ngIf="securityService.isAuthenticated();" class="p-fluid">
  <p-toast></p-toast>
  <div class="p-grid p-col-6">
    <H2>Create Person</H2>
  </div>
  <form #personForm = "ngForm">
  <div class=" p-shadow-4">
    <div style="margin-left: 2px;" class="p-grid">
      <div class="p-col-6">
        <app-validatable-dropdownlist [optionList]="personType"
                                      [labelText]="'Person Type'"
                                      name="personType"
                                      inputName="personType"
                                      [idComponent]="'id-personType'"
                                      [txtMinLength]="1"
                                      (componentHasError)="setHasPersonTypeError($event)"
                                      (valueChanged)="peronTypeChanged($event)"
                                      [(ngModel)]="personFormModel.personType">
        </app-validatable-dropdownlist>
      </div>
    </div>

    <div style="margin-bottom: 10pt;" *ngIf="personFormModel.personType==='PRIVATE'" class="p-grid">
      <div style="margin-left: 6px" class="p-col-3">
        <app-validatable-input-text [labelText]="'First name'"
                                    name = "personFirstName"
                                    inputName="personFirstName"
                                    [idComponent]="'id_firstName'"
                                    [txtMinLength]="2"
                                    (componentHasErrorEvent)="setHasFirstNameError($event)"
                                    [(ngModel)]="personFormModel.personFirstName">
        </app-validatable-input-text>
      </div>
      <div class="p-col-3">
        <app-validatable-input-text [labelText]="'Last name'"
                                    name="personLastName"
                                    inputName="personLastName"
                                    [idComponent]="'id_lastName'"
                                    [txtMinLength]="2"
                                    (componentHasErrorEvent)="setHasLastNameError($event)"
                                    [(ngModel)]="personFormModel.personLastName">
        </app-validatable-input-text>
      </div>
    </div>

    <div style="margin-bottom: 10pt" *ngIf="personFormModel.personType==='ORGANISATION'" class="p-grid">
      <div class="p-col-3">
        <app-validatable-input-text [labelText]="'Company name'"
                                    name = "companyName"
                                    inputName="companyName"
                                    [idComponent]="'id_company_Name'"
                                    [txtMinLength]="2"
                                    (componentHasErrorEvent)="setHasCompanyNameError($event)"
                                    [(ngModel)]="personFormModel.companyName">
        </app-validatable-input-text>
      </div>
    </div>
    <div style="margin-bottom: 10pt;  margin-left: 2px" class="p-grid">
      <div style="padding-left: 5px" class="p-col-3">
        <app-validatable-input-text [labelText]="'E-mail'"
                                    name = "email"
                                    [inputPattern]="emailPattern"
                                    patternErrorText="Wrong email"
                                    [idComponent]="'id_email'"
                                    [inputType]="'text'"
                                    [txtMinLength]="5"
                                    (componentHasErrorEvent)="setHasEmailError($event)"
                                    [(ngModel)]="personFormModel.email">
        </app-validatable-input-text>
      </div>
    </div>
    <div  style="margin-left: 0px !important; padding-left: 0px !important;" *ngIf="personFormModel.personType==='PRIVATE'" class="p-grid">
      <div style="padding-left: 0px" class="p-col-2">
        <app-validatable-input-text [labelText]="'Tax number'"
                                    name = "taxNumber"
                                    inputName="taxNumber"
                                    [idComponent]="'id_tax_Number'"
                                    [txtMinLength]="5"
                                    (componentHasErrorEvent)="setHasTaxNumberError($event)"
                                    [(ngModel)]="personFormModel.taxNumber">
        </app-validatable-input-text>
      </div>
    </div>
  </div>
  <div class="p-grid p-col-6">
    <H2>Person address</H2>
  </div>
  <div class=" p-shadow-4">

    <div class="p-grid">
      <div style="margin-left: 5pt" class="p-col-2">
        <app-validatable-input-text [labelText]="'Zip'"
                                    name="zipCode"
                                    inputName="zipCode"
                                    [idComponent]="'id_Zip'"
                                    [txtMinLength]="4"
                                    (componentHasErrorEvent)="setHasZipCodeError($event)"
                                    [(ngModel)]="personFormModel.personAddressFormModel.zipCode">
        </app-validatable-input-text>
      </div>
      <div style="margin-left: 5pt" class="p-col-3">
        <app-validatable-input-text [labelText]="'City'"
                                    name = "city"
                                    inputName="city"
                                    [idComponent]="'id_City'"
                                    [txtMinLength]="2"
                                    (componentHasErrorEvent)="setHasCityError($event)"
                                    [(ngModel)]="personFormModel.personAddressFormModel.city">
        </app-validatable-input-text>
      </div>
    </div>
    <div style="margin-left: 0px" class="p-grid">
      <div style="padding-left: 6px !important;" class="p-col-2">
      <span style="margin-top: 10pt" class="p-float-label">
        <input style="margin-left: 0px !Important" pInputText id="id-add-postBoxCode" type="text"
               name="postBoxCode"
               [(ngModel)]="personFormModel.personAddressFormModel.postBoxCode"/>
        <label for="id-add-postBoxCode">Post Box</label>
      </span>
      </div>
      <div style="margin-left: 5pt" class="p-col-3">
        <div style="margin-top: 15pt">
          <app-validatable-input-text [labelText]="'Street'"
                                      name = "street"
                                      inputName="street"
                                      [idComponent]="'id_Street'"
                                      [txtMinLength]="2"
                                      (componentHasErrorEvent)="setHasStreetError($event)"
                                      [(ngModel)]="personFormModel.personAddressFormModel.street">
          </app-validatable-input-text>
        </div>
      </div>

    </div>
  </div>
  <div class="p-grid">
    <div class="p-col-6">
      <H2>Person bank account</H2>
    </div>
  </div>
  <div class=" p-shadow-4">
    <div class="p-grid">
      <div style="margin-top: 5pt; margin-left: 5pt" class="p-col-4">
        <app-validatable-input-text [labelText]="'Bank name'"
                                    name = "bankName"
                                    inputName="bankName"
                                    [idComponent]="'id_BankName'"
                                    [txtMinLength]="2"
                                    (componentHasErrorEvent)="setHasBankNameError($event)"
                                    [(ngModel)]="personFormModel.bankAccountFormModel.bankName">
        </app-validatable-input-text>
      </div>

      <div class="p-col-2">
      <span class="p-float-label">
        <input pInputText id="id_AccountNumber" type="text"
               name="accountNumber"
               [(ngModel)]="personFormModel.bankAccountFormModel.accountNumber"/>
        <label for="id_AccountNumber">Account number</label>
      </span>
      </div>
    </div>

    <div class="p-grid">
      <div style="margin-left: 4pt; margin-top: 8pt" class="p-col-4">
        <div style="display: table; width: 100%;">
          <div style="display: table-row; width: 100%;">
            <div style="display: table-cell; width: 100%;">
               <span class="p-float-label">
                    <input class="ng-dirty p-mr-2"
                           pInputText
                           required
                           name ="iban"
                           id="id_IBAN"
                           type="text"
                           [ngModel]="personFormModel.bankAccountFormModel.iban | ibanFormatter"
                           (ngModelChange)="personFormModel.bankAccountFormModel.iban = $event"
                           ibanValidator
                           #modelRef="ngModel"/>
                  <label for="id_IBAN">IBAN</label>
               </span>
            </div>
            <div id="id_Iban_Required_err" *ngIf="modelRef.errors?.required" style="display: table-cell; width: 10%; margin-left: 2px;">
              <p-message severity="error"></p-message>
            </div>
            <div id="id_Iban_Iban_err"  *ngIf="setHasIbahError(modelRef.errors?.iban!==null, modelRef.errors?.iban)"
                 style="display: table-cell; width: 10%; margin-left: 2px">
              <p-message severity="error"></p-message>
            </div>
            <ng-template *ngIf="modelRef?.valid">
              <ng-template *ngIf="setHasIbahError(false, modelRef.errors?.iban)"/>
            </ng-template>
          </div>
          <div *ngIf="modelRef.errors?.iban" class="alert alert-danger">
            Wrong IBAN
          </div>
        </div>
      </div>

      <div style="margin-left: 5pt; margin-top: 12pt" class="p-col-2">
        <app-validatable-input-text [labelText]="'BIC/SWIFT'"
                                    name = "bicSwift"
                                    inputName="bicSwift"
                                    [idComponent]="'id-acc-bicSwift'"
                                    [txtMinLength]="5"
                                    (componentHasErrorEvent)="setHasBicError($event)"
                                    [(ngModel)]="personFormModel.bankAccountFormModel.bicSwift">
        </app-validatable-input-text>
      </div>
    </div>
  </div>
  <div style="margin-top:5px;" class="p-grid">
    <div class="p-col-1">
    <p-button [disabled]="personForm.invalid" label="Save" (onClick)="savePerson($event)"></p-button>
    </div>
  </div>
  </form>
</div>


TypeScript (component controller)

.........

@Component({
  selector: 'app-edit-person-dialog',
  standalone: true,
  imports: [CommonModule, ReactiveFormsModule, AngularIbanModule, ButtonModule, InputTextModule, MessageModule, ToastModule, ValidatableDropdownlistModule, ValidatableInputTextModule, DropdownModule, DialogModule],
  templateUrl: './edit-person-dialog.component.html',
  styleUrls: ['./edit-person-dialog.component.css']
})
export class EditPersonDialogComponent {
  /** person model */
  //personFormModel: PersonFormModel = new PersonFormModel();ƒ
  originalPersonFormModel: PersonFormModel = new PersonFormModel();
  /**true if no changes in edited person happens*/
  isNoChangesInPersonModel: boolean = true
  /**person type model*/
  personType: DropdownDataType[] = [
    // {label: '[Select person type]', value: ''},
    {label: 'Private person', value: 'PRIVATE'},
    {label: 'Organisation', value: 'ORGANISATION'}
  ];
  /**person form group*/
  editPersonFG: FormGroup
  @Input() visible: boolean = false
  @Output() visibilityChanged = new EventEmitter<boolean>
  @Output() personModelChanges = new EventEmitter<PersonFormModel>

  /**
   * Constructor
   *
   * @param securityService the security service
   * @param formBuilder form builder
   */
  constructor(public securityService: AppSecurityService, private formBuilder: FormBuilder, private messagePrinter: MessagesPrinter) {
    this.editPersonFG = this.formBuilder.group({
      personId: this.formBuilder.nonNullable.control(null),
      personLastName: this.formBuilder.nonNullable.control(''),
      personFirstName: this.formBuilder.nonNullable.control(''),
      companyName: this.formBuilder.nonNullable.control(''),
      personType: this.formBuilder.nonNullable.control('', [Validators.required]),
      taxNumber: this.formBuilder.nonNullable.control(''),
      email: this.formBuilder.nonNullable.control('', [Validators.required,
        Validators.minLength(5),
        Validators.pattern('[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}')]),
      personAddressFormModel: this.formBuilder.group({
        city: this.formBuilder.nonNullable.control('', [Validators.required]),
        street: this.formBuilder.nonNullable.control('', [Validators.required]),
        zipCode: this.formBuilder.nonNullable.control('', [Validators.required]),
        postBoxCode: this.formBuilder.nonNullable.control(null)
      }),
      bankAccountFormModel: this.formBuilder.group({
        accountNumber: this.formBuilder.nonNullable.control(null),
        iban: this.formBuilder.nonNullable.control(null, [Validators.required,
          ValidatorService.validateIban]),
        bicSwift: this.formBuilder.nonNullable.control('', [Validators.required]),
        bankName: this.formBuilder.nonNullable.control('', [Validators.required])
      })
    })
  }



  setVisible(val: boolean) {
    this.visibilityChanged.emit(val)
  }

  personTypeChanged(e: any) {
    const personTypeFg = this.editPersonFG.get('personType') as FormControl
    personTypeFg.setValue(e.value)
  }

  /**
   * The full path to the control in form group.
   *
   * @param controlPath the path to control with avoiding the root form group
   */
  getControl(controlPath: string) {
    //console.log('Try read control with PATH : '+controlPath)
    return this.editPersonFG.get(controlPath) as FormControl;
  }

  haveErrors(): boolean {
    return this.editPersonFG.invalid
  }

  setPerson(personFormModel: PersonFormModel) {
    this.isNoChangesInPersonModel = true
    this.originalPersonFormModel = personFormModel
    this.getControl('personId').setValue(personFormModel.id)
    if (personFormModel.personType === 'ORGANISATION') {
      this.getControl('personFirstName').clearValidators()
      this.getControl('personLastName').clearValidators()
      this.getControl('taxNumber').clearValidators()
      this.getControl('companyName').setValidators([Validators.required, Validators.minLength(2)])
      this.editPersonFG.updateValueAndValidity()
    } else if (personFormModel.personType === 'PRIVATE') {
      this.getControl('personFirstName').setValidators([Validators.required, Validators.minLength(2)])
      this.getControl('personLastName').setValidators([Validators.required, Validators.minLength(2)])
      this.getControl('taxNumber').setValidators([Validators.required, Validators.minLength(2)])
      this.getControl('companyName').clearValidators()
      this.editPersonFG.updateValueAndValidity()
    }

    this.getControl('personFirstName').setValue(personFormModel.personFirstName)
    this.getControl('personLastName').setValue(personFormModel.personLastName)
    this.getControl('personType').setValue(personFormModel.personType)
    this.getControl('companyName').setValue(personFormModel.companyName)
    this.getControl('email').setValue(personFormModel.email)
    this.getControl('taxNumber').setValue(personFormModel.taxNumber)
    this.getControl('personAddressFormModel.city').setValue(personFormModel.personAddressFormModel.city)
    this.getControl('personAddressFormModel.postBoxCode').setValue(personFormModel.personAddressFormModel.postBoxCode)
    this.getControl('personAddressFormModel.zipCode').setValue(personFormModel.personAddressFormModel.zipCode)
    this.getControl('personAddressFormModel.street').setValue(personFormModel.personAddressFormModel.street)
    this.getControl('bankAccountFormModel.accountNumber').setValue(personFormModel.bankAccountFormModel.accountNumber)
    this.getControl('bankAccountFormModel.bankName').setValue(personFormModel.bankAccountFormModel.bankName)
    this.getControl('bankAccountFormModel.iban').setValue(personFormModel.bankAccountFormModel.iban)
    this.getControl('bankAccountFormModel.bicSwift').setValue(personFormModel.bankAccountFormModel.bicSwift)
    this.editPersonFG.updateValueAndValidity()
  }

  mapFromGroupToPersonModel() {
    const personModel: PersonFormModel = new PersonFormModel()

    personModel.personType = this.getControl('personType').value?.trim();
    personModel.id = this.getControl('personId').value;
    if (personModel.personType === 'ORGANISATION') {
      personModel.companyName = this.getControl('companyName').value?.trim()
      this.validateChanges(this.originalPersonFormModel.companyName?.trim() === personModel.companyName?.trim())
    } else if (this.getControl('personType').value === 'PRIVATE') {
      personModel.personFirstName = this.getControl('personFirstName').value?.trim()
      this.validateChanges(this.originalPersonFormModel.personFirstName?.trim() === personModel.personFirstName?.trim())
      personModel.personLastName = this.getControl('personLastName').value?.trim()
      this.validateChanges(this.originalPersonFormModel.personLastName?.trim() === personModel.personLastName?.trim())
      personModel.taxNumber = this.getControl('taxNumber').value?.trim()
      this.validateChanges(this.originalPersonFormModel.taxNumber?.trim() === personModel.taxNumber?.trim())
    }
    personModel.email = this.getControl('email').value?.trim()
    this.validateChanges(this.originalPersonFormModel.email?.trim() === personModel.email?.trim())
    personModel.taxNumber = this.getControl('taxNumber').value?.trim()
    this.validateChanges(this.originalPersonFormModel.taxNumber?.trim() === personModel.taxNumber?.trim())
    personModel.personAddressFormModel.city = this.getControl('personAddressFormModel.city').value?.trim()
    this.validateChanges(this.originalPersonFormModel.personAddressFormModel.city?.trim() === personModel.personAddressFormModel.city?.trim())
    personModel.personAddressFormModel.postBoxCode = this.getControl('personAddressFormModel.postBoxCode').value?.trim()
    this.validateChanges(this.originalPersonFormModel.personAddressFormModel.postBoxCode?.trim() === personModel.personAddressFormModel.postBoxCode?.trim())
    personModel.personAddressFormModel.zipCode = this.getControl('personAddressFormModel.zipCode').value?.trim()
    this.validateChanges(this.originalPersonFormModel.personAddressFormModel.zipCode?.trim() === personModel.personAddressFormModel.zipCode?.trim())
    personModel.personAddressFormModel.street = this.getControl('personAddressFormModel.street').value?.trim()
    this.validateChanges(this.originalPersonFormModel.personAddressFormModel.street?.trim() === personModel.personAddressFormModel.street?.trim())
    personModel.bankAccountFormModel.accountNumber = this.getControl('bankAccountFormModel.accountNumber').value
    this.validateChanges(this.originalPersonFormModel.bankAccountFormModel.accountNumber?.trim() === personModel.bankAccountFormModel.accountNumber?.trim())
    personModel.bankAccountFormModel.bankName = this.getControl('bankAccountFormModel.bankName').value?.trim()
    this.validateChanges(this.originalPersonFormModel.bankAccountFormModel.bankName?.trim() === personModel.bankAccountFormModel.bankName?.trim())
    personModel.bankAccountFormModel.iban = this.getControl('bankAccountFormModel.iban').value
    this.validateChanges(this.originalPersonFormModel.bankAccountFormModel.iban?.trim() === personModel.bankAccountFormModel.iban?.trim())
    personModel.bankAccountFormModel.bicSwift = this.getControl('bankAccountFormModel.bicSwift').value?.trim()
    this.validateChanges(this.originalPersonFormModel.bankAccountFormModel.bicSwift?.trim() === personModel.bankAccountFormModel.bicSwift?.trim())

    return personModel
  }

  validateChanges(isEquals: boolean) {
    this.isNoChangesInPersonModel = this.isNoChangesInPersonModel&&isEquals
  }


  /**
   * Sends the changes back to the person management form after successful changes of person
   */
  sendChanges() {

    if (this.editPersonFG.valid) {
      const model = this.mapFromGroupToPersonModel();
      console.log(" Result: "+JSON.stringify(model))
      console.log('is no changes? :'+this.isNoChangesInPersonModel)
      if(this.isNoChangesInPersonModel === true) {
        this.messagePrinter.printUnsuccessefulMessage("The person data has no changes.", null)
      } else {
        this.personModelChanges.emit(model)
        this.visibilityChanged.emit(false)
      }
    }
  }
}

I expect to have a solution for template-driven form if it possible. If that not possible than I will migrate to Reactive-Form.

0

There are 0 answers