【问题标题】:Custom Angular2 Validator only evaluates when the page loads, and not when the object is updated自定义 Angular2 验证器仅在页面加载时评估,而不是在对象更新时评估
【发布时间】:2016-12-22 05:37:09
【问题描述】:

我正在尝试使用标签验证表单,其中列表必须包含至少一个标签才能有效。但它只评估页面何时加载,而不是更新。

https://plnkr.co/edit/umnhybKhNEjswrUJGh3q?p=preview

验证函数:

function notEmpty(control) {
  if(control.value == null || control.value.length===0) {
    return {
      notEmpty: true
    }
  }

  return null;
}

使用验证器的组件和模板:

@Component({
  selector: 'my-app',
  template: `
    <form [formGroup]="myForm">
    <div>
    (Comma Separated, no duplicates allowed. Enter also submits a tag.)
    <div tags formControlName="list" [(ngModel)]="list"> </div>
       <div *ngIf="myForm.get('list').valid">List 1 Not Empty.</div>
    <div tags formControlName="list2" [(ngModel)]="list2"> </div>
       <div *ngIf="myForm.get('list2').valid">List 2 Not Empty.</div>
    </div>
    </form>
  `,
})
export class App {
  list:Array<string>;
  list2:Array<string>;
  myForm:FormGroup;
  myList:FormControl;
  myList2:FormControl;
  constructor(private fb: FormBuilder) {
    this.list = [];
    this.list2 = ["test"];
    this.myList = fb.control('', notEmpty);
    this.myList2 = fb.control('', notEmpty);
    this.myForm = fb.group({
      list: this.myList,
      list2: this.myList2
      });
  }

  addItem(item:string) {
    this.list.push(item);
  }
}

标签组件和其他子组件:

const MY_PROVIDER = {
    provide: NG_VALUE_ACCESSOR,
    useExisting: forwardRef(()=> Tags),
    multi: true
  };

@Component({
  selector: 'tags, [tags]',
  template: ` 
  <div>
    <tag-item *ngFor="let item of tagsList" item="{{item}}" (remove)="removeTag(item)"></tag-item>
    <input class="tagInput" #tagInput
         (focus)="focus()"
         [(ngModel)]="current"
         (keydown)="keyDown($event)"
         (keyup)="keyUp($event)"
         (blur)="blur()"
         placeholder="+ Tag"/>
  </div>
  `,
  providers: [MY_PROVIDER]
})
export class Tags implements ControlValueAccessor {
  tagsList : Array<string>;
  current : string;
  @ViewChild('tagInput') child;
  inFocus : boolean = false;

  constructor() {
    this.current = "";
    this.tagsList = new Array<string>();
  }

  focus() {
    this.child.nativeElement.focus();
    this.inFocus = true;
  }

  keyDown(event:KeyboardEvent) {
    if (event.keyCode === 188 || event.keyCode === 13) { //188 is Comma, 13 is Enter, 32 is Space.
      this.pushTag();
    }  else if (event.keyCode === 8 && this.current.length == 0 && this.tagsList.length > 0){
      this.current = this.tagsList.pop();
    }
  }

  keyUp(event:KeyboardEvent) {
    if(event.keyCode === 188) {
      this.current = '';
    }
  }

  pushTag() {
    let str = this.current;
    this.current = '';
    if(str.trim() != '') {
      for(let s of str.split(',')) {
        s = this.sanitize(s);
        if(s.trim() != '') {
          if(!this.tagsList.some(x => x.toLowerCase() === s.toLowerCase()))
            this.tagsList.push(s);
        }
      }
    }
  }

  sanitize(str: string) : string {
    let s = str;
    s = s.replace('\'', '').replace('"', '').replace(';', '');
    return s;
  }

  blur() {
    this.pushTag();
    this.inFocus = false;
  }

  removeTag(value) {
    let index = this.tagsList.indexOf(value, 0);
    if (index > -1) {
       this.tagsList.splice(index, 1);
     }
  }

  clear() {
    this.tagsList = new Array<string>();
  }

    get value(): Array<string> { return this.tagsList; };
    set value(v: Array<string>) {
      if (v !== this.tagsList) {
        this.tagsList = v;
        this.onChange(v);
        this.onTouched();
      }
    }

    writeValue(value: Array<string>) {
      this.tagsList = value;
      this.onChange(value);
    }

    onChange = (_) => {};
    onTouched = () => {};
    registerOnChange(fn: (_: any) => void): void { this.onChange = fn; }
    registerOnTouched(fn: () => void): void { this.onTouched = fn; }
}

@Component({
  selector: 'tag-item, [tag-item]',
  template: `{{item}}   <delete-me (click)="removeTag(item)">x</delete-me>`
})
export class TagItem {
  @Input() item : string;
  @Output() remove : EventEmitter<string> = new EventEmitter();

  removeTag(item) {
    this.remove.emit(item);
  }
}

@Component({
  selector:'delete-me',
  template:'x'
})
export class DeleteIcon {

}

【问题讨论】:

  • 我想问题出在你在做this.list.push(item);之类的任何地方。由于您正在改变数组而不是使用新数组重新分配,Angular2 可能不知道发生了更改。检查this answer 以获取可能的解决方案。

标签: validation angular typescript


【解决方案1】:

这似乎有效。

...//Tags Component pushMethod
pushTag() {
    let str = this.current;
    this.current = '';
    if(str.trim() != '') {
      for(let s of str.split(',')) {
        s = this.sanitize(s);
        if(s.trim() != '') {
          if(!this.tagsList.some(x => x.toLowerCase() === s.toLowerCase())) {
            this.tagsList.push(s);
            this.pushed.emit(s); // created an EventEmitter<string>
          }
        }
      }
    }
  }

在我的主要组件中:

@Component({
  selector: 'my-app',
  template: `
    <form [formGroup]="myForm">
    <div>
    (Comma Separated, no duplicates allowed. Enter also submits a tag.)
    <div tags formControlName="list" (pushed)="update()" [(ngModel)]="list"> </div>
       <div *ngIf="myForm.get('list').valid">List 1 Not Empty.</div>
    <div tags formControlName="list2" (pushed)="update()" [(ngModel)]="list2"> </div>
       <div *ngIf="myForm.get('list2').valid">List 2 Not Empty.</div>
    </div>
    </form>
  `,
})
export class App {
  list:Array<string>;
  list2:Array<string>;
  myForm:FormGroup;
  myList:FormControl;
  myList2:FormControl;
  constructor(private fb: FormBuilder) {
    this.list = [];
    this.list2 = ["test"];
    this.myList = fb.control('', notEmpty);
    this.myList2 = fb.control('', notEmpty);
    this.myForm = fb.group({
      list: this.myList,
      list2: this.myList2
      });
  }

  update() {
    this.myList.updateValueAndValidity();
    this.myList2.updateValueAndValidity();
  }

  addItem(item:string) {
    this.list.push(item);
  }
}

不过,这似乎有点老套,所以我仍然想要一个更好的答案,如果有的话。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-11-21
    • 2012-12-22
    • 2016-12-04
    • 2019-09-26
    • 2019-12-12
    • 2019-08-16
    相关资源
    最近更新 更多