【问题标题】:Two way binding of ngModel between components with validation带有验证的组件之间 ngModel 的两种方式绑定
【发布时间】:2018-05-24 15:49:29
【问题描述】:

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

parent-component.ts

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

父组件.html

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

子组件.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>

子组件.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 -> 不符合要求的最小长度 3。所以我收到一条错误消息。但父 profile.name 与输入 A 绑定

所以我在代码中做了修改

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,现在我已经清除了验证,所以我在 profile.name 中获得了价值

如果我输入数字 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;
      });
    }

}

【问题讨论】:

  • 请考虑使用ngDoCheck,你也在其中使用setTimeout。这个钩子将被触发 20 次鼠标移动
  • 这是stackoverflow中规定的答案。是的。它填满了我的控制台,还有其他提示性代码方法吗,因为我将使用 10-15 个字段,这些字段可在 5-6 页中重复使用
  • 对不起,我没明白

标签: angular validation


【解决方案1】:

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

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() {

  }
}

堆栈闪电战:https://stackblitz.com/edit/angular-emq3ef?file=app%2Fprofile-name%2Fprofile-name.component.ts

【讨论】:

  • 它绑定我输入的任何内容。我希望该值仅在其有效时才被绑定。如果无效,则父变量应为空。但是子变量有它的价值。
  • 我添加了lastIsInvalid 标志,请查看我的更新答案。我还创建了一个 STACKBLITZ (stackblitz.com/edit/…),如果您的问题仍然存在,请更新我的 stackblitz,我会尽力提供帮助
  • 嗨..感谢您的努力,这正是我想要的。我将您的代码复制并粘贴到我的项目文件中,我最终进入了我的项目中的无限循环。我没有改变任何东西,我用stackblitz代码交叉引用......你能指导我为什么我会以无限循环结束。 dropbox.com/s/lv0j8xemnrs9326/2017-12-11_18h10_58.mp4?dl=0
  • 请给我一些关于在setTimeout中使用_的信息 setTimeout(_
  • 我通常使用下划线 (_) 作为强制参数名称,它不会在其功能块的任何地方使用。在这个 setTimeout 的特定示例中,它只是替换了 () =&gt; .... 语法。
猜你喜欢
  • 2021-10-16
  • 2020-07-12
  • 2011-07-18
  • 2019-01-22
  • 2020-07-07
  • 2018-04-14
  • 2017-08-06
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多