如何在Angular2 Typescript中更改HTML元素readonly和required属性?

时间:2016-02-04 21:59:53

标签: typescript angular

对于我的一些组件,我想要来回读取输入字段和来回的必需属性。

我设法得到一个正在运行的代码,可以根据需要更改它们,但问题是它只适用于readonly,但似乎没有按要求工作:虽然元素属性更改为所需的Angular2仍然认为fieldCtrl有效。

这是我的傻瓜,我在这里说明了这个问题:https://plnkr.co/edit/Yq2RDzUJjLPgReIgSBAO?p=preview

//our root app component
import {Component} from 'angular2/core'

@Component({
  selector: 'my-app',
  providers: [],
  template: `
    <div>
    <form #f="ngForm">
      <button type="button" (click)="toggleReadOnly()">Change readonly!</button>
      <button type="button" (click)="toggleRequired()">Change required!</button>
      <input id="field" [(ngModel)]="field" ngControl="fieldCtrl" #fieldCtrl="ngForm"/>
      {{fieldCtrl.valid}}
    </form>
    </div>
  `,
  directives: []
})
export class App {
  constructor() {
    this.name = 'Angular2'
  }

  toggleRequired(){
    this.isRequired = !this.isRequired;
    var fieldElement = <HTMLInputElement>document.getElementById('field');
    if (this.isRequired){
      fieldElement.required = true;
      this.field = "it's required now";
    }
    else{
      fieldElement.required = false;
      this.field = "can leave it blank";
    }
  }

  toggleReadOnly(){
    this.isReadOnly = !this.isReadOnly;
    var fieldElement = <HTMLInputElement>document.getElementById('field');
    if (this.isReadOnly){
      fieldElement.readOnly = true;
      this.field = "it's readonly now";
    }
    else{
      fieldElement.readOnly = false;
      this.field = "feel free to edit";
    }
  }

  private isReadOnly:boolean=false;

  private field:string = "feel free to edit";

  private isRequired:boolean=false;

}

更新: 试过建议的方法

[required]="isRequired" [readonly]="isReadOnly"

它就像readonly的魅力一样,并且对于required = true,但我不能再关闭所需的属性 - 它显示空字段无效,尽管不再需要。

更新了plunker:https://plnkr.co/edit/6LvMqFzXHaLlV8fHbdOE

UPDATE2: 试过建议的方法

[required]="isRequired ? true : null"

它确实逐个元素地添加/删除了必需的属性,但是对于不需要的空字段,字段控制器的有效属性显示为false。

在Angular2 Typescript中更改所需属性的正确方法是什么?

3 个答案:

答案 0 :(得分:33)

对于要删除的绑定属性,需要将它们设置为null。有一个讨论要改变它以删除,但它被拒绝了,至少目前是这样。

 [required]="isRequired ? '' : null"

 [required]="isRequired ? 'required' : null"

由于[]周围缺少ngControl,您的Plunker会产生错误。

有关工作示例,请参阅此Plunker

另见Deilan的评论。

答案 1 :(得分:5)

您似乎已经有了添加/删除readonly属性的答案。对于required属性,我建议创建一个服务来跟踪验证器的启用/禁用状态,然后在绑定到验证控件时利用该服务。

状态验证器

该类负责跟踪验证器及其启用/禁用状态。

export class StateValidator {
    public enabled: boolean = true;
    validator: (control: Control) => { [key: string]: boolean };
    constructor(validator: (control: Control) => 
        { [key: string]: boolean }, enabled: boolean) {
        this.enabled = enabled;
        this.validator = validator;

    }

    enable() {
        this.enabled = true;
    }
    disable() {
        this.enabled = false;
    }
    toggle() {
        this.enabled = !this.enabled;
    }
    get() {
        return (control: Control) => {
            if (this.enabled)
                return this.validator(control);
            return null;
        }
    }
}

它具有启用,禁用或切换验证器的方法;还有一个get方法,它返回一个新的验证器函数,如果启用了验证器,它将在调用时调用底层验证器函数,或者在未启用验证器时返回null。

验证服务

此类是一个单例服务,负责按键注册验证器,以及支持基于该密钥启用,禁用或切换验证器的方法。

export class ValidationService {
    validators: { [key: string]: StateValidator } = {};
    register(key: string, validator: Function): Function {
        var stateValidator = new StateValidator(<(control: Control) => { [key: string]: boolean }>validator, true);
        this.validators[key] = stateValidator;
        return stateValidator.get();
    }
    enable(key: string) {
        this.validators[key].enable();
    }
    disable(key: string) {
        this.validators[key].disable();
    }
    toggle(key: string) {
        this.validators[key].toggle();
    }
    list() {
        var l = [];
        for (var key in this.validators) {
            if (this.validators.hasOwnProperty(key)) {
                l.push({ key: key, value: this.validators[key].enabled });
            }
        }
        return l;
    }
}

该服务还有一个list函数,用于返回键/值对列表,其中键表示已注册的验证器键,值为布尔值指示符,表示验​​证器的启用状态。

组件

要使用ValidationService,请在bootstrap期间使用根注入器注册服务:

bootstrap(AppComponent, [ValidationService]);

或者使用组件级注入器注册服务:

@Component({
  selector: 'app',
  providers: [ValidationService],
  ...
})

然后在组件的构造函数中注入服务:

export class AppComponent {
    form: ControlGroup;
    constructor(public validationService:ValidationService) {
      ...
    }
}

接下来,像往常一样绑定到验证控件,除了使用ValidationService注册并返回状态验证器:

new Control('', validationService.register('required', Validators.required));

此解决方案的一大优点是,您可以轻松地将状态验证器与其他内置或自定义验证器进行组合和混合:

this.form = new ControlGroup({
    name: new Control('hello',
        Validators.compose([
            validationService.register('required', Validators.required),
            validationService.register('minlength', Validators.minLength(4)),
            Validators.maxLength(10)]))

});

切换验证器

使用该服务切换验证器的状态:

validationService.toggle('required');

以下是如何绑定到表中的状态验证器列表,并将切换功能连接到按钮单击事件的示例:

<table>
  <tr>
     <td>Validator</td>
     <td>Is Enabled?</td>
     <td></td>
  </tr>
  <tr *ngFor="#v of validationService.list()">
     <td>{{v.key}}</td>
     <td>{{v.value }}</td>
     <td><button (click)="validationService.toggle(v.key)">Toggle</button></td>
  </tr>
</table>

Demo Plnkr

enter image description here

答案 2 :(得分:2)

我使用的替代解决方案:

import {Directive, ElementRef, Input} from '@angular/core';

@Directive({
    selector: '[symToggleRequired]'
})
export class ToggleRequiredDirective {
    @Input() public set symToggleRequired(condition: boolean) {
        if (condition) {
            (<HTMLElement>this.element.nativeElement).setAttribute('required', 'true');
        } else {
            (<HTMLElement>this.element.nativeElement).removeAttribute("required");
        }
    } 

    constructor(
        private element: ElementRef
    ) { } 
}

在html元素上使用此指令删除或添加必需属性:

<input [symToggleRequired]='FlagPropertyOfYourComponent'>