通过验证在组件之间双向绑定ngModel

时间:2017-12-11 06:31:55

标签: angular validation

我正在尝试将父组件中的值绑定到子组件,以便它可以重用。

父 - component.ts

 profile:any = {name:"", mobile:""}

父-component.html

<app-profile-name label="Name" [(name)]="profile.name"></app-profile-name>

child component.html

<div class="form-group">
    <label for="">Name</label>
    <input type="text" class="form-control" [(ngModel)]="name" appUppercase
     required minlength="3" maxlength="50" pattern="[a-zA-Z\s\.]*" #nameInput="ngModel" (keyup)="onKeyup($event)">
    <div *ngIf="nameInput.invalid && (nameInput.dirty || nameInput.touched)" class="form-control-text text-danger animated fadeIn">
      <small *ngIf="nameInput.errors.required" class="d-block">Name is required</small>
      <small *ngIf="nameInput.errors.pattern" class="d-block">Alphabets dot and space is only allowed</small>
      <small *ngIf="nameInput.errors.minlength" class="d-block">Name should be minimum 3 characters</small>
      <small *ngIf="nameInput.errors.maxlength" class="d-block">Name should be maximum 3 characters</small>
    </div>
  </div>

Child component.ts

import { Component, OnInit, Input, Output, EventEmitter, DoCheck, ViewChild } from '@angular/core';

@Component({
  selector: 'app-profile-name',
  templateUrl: './profile-name.component.html',
  styleUrls: ['./profile-name.component.css']
})
export class ProfileNameComponent implements OnInit, DoCheck {

  @Input() name: String;
  @Output() nameChange: EventEmitter<any> = new EventEmitter();
  @ViewChild('nameInput') nameInput:any;
  constructor() { }

  ngOnInit() {

  }

  ngDoCheck() {
    setTimeout(()=>{      
      this.nameChange.next(this.name);
    });

  }

}

这段代码非常好用。

以下是验证失败但仍能看到数据绑定的测试输入案例

  1. A - &gt;与最小长度3的要求不匹配。所以我收到一条错误消息。但父profile.name与输入A
  2. 绑定

    所以我在代码中进行了修改

    ngDoCheck() {
        setTimeout(()=>{      
          if(this.nameInput.invalid){ // added this if condition
            this.nameChange.next("")
            return;
          }
          this.nameChange.next(this.name);
        });
    
      }
    

    以下是以下案例

    现在,如果我按A并且由于验证最小长度3不符合,我将获得空的profile.name

    如果我输入A1ASDF,由于验证失败,我将获得空的profile.name。

    现在,如果我输入ALAKS,现在我已经清除了验证,因此我在我的个人资料中获得了价值。名称

    如果我输入数字1,将设置ALAKS1,它将失败验证。所以我的profile.name同时转到“”,this.name也消失了,我得到一个空的输入框。

    问题是如何恢复输入框值并仅获取父组件中的有效输入值。

    希望我明白这个问题。

    工作答案 特别感谢@Andiry。

    当我最终进入无限循环时,我将@Andiry的逻辑变为模糊,现在它的工作正常。

    这是更新后的代码

     <input type="text" class="form-control" [(ngModel)]="name" appUppercase
         required minlength="3" maxlength="50" pattern="[a-zA-Z\s\.]*" #nameInput="ngModel" (blur)="onInputBlur()">
    

    profile-name.component.ts文件

    import { Component, OnInit, Input, Output, EventEmitter, ViewChild } from '@angular/core';
    
    @Component({
      selector: 'app-profile-name',
      templateUrl: './profile-name.component.html',
      styleUrls: ['./profile-name.component.css']
    })
    export class ProfileNameComponent implements OnInit {
    
      @Input() name:string;
      @Output() nameChange: EventEmitter<any> = new EventEmitter();
      @ViewChild('nameInput') nameInput:any;
    
      constructor() { }
    
        ngOnInit() {
    
        }
    
        onInputBlur(){
          let name = this.name;
            this.nameChange.emit(this.nameInput.invalid ? '' : this.name);
          setTimeout(()=>{
            this.name = name;
          });
        }
    
    }
    

1 个答案:

答案 0 :(得分:0)

尝试将您的子组件重写为:

export class ProfileNameComponent implements OnInit, DoCheck {
  nameValue: string;
  lastIsInvalid: boolean = true;

  @Input() get name() {
    return this.nameValue;
  }
  @Output() nameChange: EventEmitter<any> = new EventEmitter();

  set name(val) {
    let name = val;
    setTimeout(_ => {
      this.nameValue = val;
      this.nameChange.emit(this.nameInput.invalid ? '' : this.nameValue);
      if (this.lastIsInvalid !== this.nameInput.invalid) {
        setTimeout(_ => this.name = name);
      }
      this.lastIsInvalid = this.nameInput.invalid;
    });
  }

  @ViewChild('nameInput') nameInput:any;

  constructor() { }

  ngOnInit() {

  }
}

STACKBLITZ:https://stackblitz.com/edit/angular-emq3ef?file=app%2Fprofile-name%2Fprofile-name.component.ts