For some of my components I would like to change input field readonly and required attributes back and forth.
对于我的一些组件,我想改变输入字段readonly和来回的必需属性。
I've managed to get a running code, that changes both of them on demand, but problem is that it works for readonly, but seems not to be working on required: although element attribute changes to required Angular2 still thinks fieldCtrl is valid.
我已经设法得到一个正在运行的代码,它可以根据需要更改它们,但问题是它只适用于readonly,但似乎没有按要求工作:虽然元素属性更改为所需的Angular2仍然认为fieldCtrl是有效的。
Here is my plunker, where I illustrated this problem: https://plnkr.co/edit/Yq2RDzUJjLPgReIgSBAO?p=preview
这是我的plunker,我在这里说明了这个问题: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;
}
UPDATE: Tried suggested method
更新:尝试建议的方法
[required]="isRequired" [readonly]="isReadOnly"
And it works like a charm for readonly, and for required=true, but I can't turn the required attribute off anymore - it shows empty field is invalid allthough not required anymore.
它就像readonly的魅力一样,并且对于required = true,但我不能再关闭所需的属性 - 它显示空字段无效,尽管不再需要。
Updated plunker: https://plnkr.co/edit/6LvMqFzXHaLlV8fHbdOE
更新的plunker:https://plnkr.co/edit/6LvMqFzXHaLlV8fHbdOE
UPDATE2: Tried suggested method
UPDATE2:尝试建议的方法
[required]="isRequired ? true : null"
It does add/remove required attribute from element by demand, however field controller's valid property shows false for empty field that is not required.
它确实按要求添加/删除所需的属性,但是对于不需要的空字段,字段控制器的有效属性显示为false。
What would be correct way of changing required attribute in Angular2 Typescript?
在Angular2 Typescript中更改所需属性的正确方法是什么?
3 个解决方案
#1
29
For bound attributes to be removed they need to be set to null. There was a discussion to change it to remove on false but it was declined, at least for now.
对于要删除的绑定属性,需要将它们设置为null。有一个讨论要改变它以删除虚假,但它被拒绝,至少现在。
[required]="isRequired ? '' : null"
or
要么
[required]="isRequired ? 'required' : null"
Your Plunker produces an error because of missing []
around ngControl
.
由于在ngControl周围缺少[],您的Plunker会产生错误。
See also this Plunker for a working example
有关工作示例,请参阅此Plunker
See also Deilan's comments below.
另见Deilan的评论如下。
#2
5
It seems you already have an answer for adding/removing the readonly attribute. For the required attribute, I suggest creating a service to keep track of the enabled/disabled state of the validator, and then to leverage the service when binding to your validation controls.
您似乎已经有了添加/删除readonly属性的答案。对于required属性,我建议创建一个服务来跟踪验证器的启用/禁用状态,然后在绑定到验证控件时利用该服务。
State Validator
This class is responsible for keeping track of the validator and its enabled/disabled state.
该类负责跟踪验证器及其启用/禁用状态。
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;
}
}
}
It has methods to enable, disable, or toggle the validator; and also a get
method that returns a new validator function, which when invoked will call the underlying validator function if the validator is enabled, or return null when the validator is not enabled.
它具有启用,禁用或切换验证器的方法;还有一个get方法,它返回一个新的验证器函数,如果启用了验证器,它将在调用时调用底层验证器函数,或者在未启用验证器时返回null。
Validation Service
This class is a singleton service responsible for registering validators by key, and supporting methods to enable, disable, or toggle a validator based on that key.
此类是一个单件服务,负责按键注册验证器,以及支持基于该密钥启用,禁用或切换验证器的方法。
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;
}
}
The service also has a list
function for returning a list of key/value pairs where the key represents the registered validator key, and the value is a Boolean indicator that represents the validator's enabled state.
该服务还具有一个列表函数,用于返回键/值对列表,其中键表示已注册的验证器键,该值是表示验证器启用状态的布尔指示符。
Component
To use the ValidationService
, register the service with the root injector during bootstrap:
要使用ValidationService,请在引导期间使用根注入器注册服务:
bootstrap(AppComponent, [ValidationService]);
Or register the service with the component-level injector:
或者使用组件级注入器注册服务:
@Component({
selector: 'app',
providers: [ValidationService],
...
})
Then inject the service in your component's constructor:
然后在组件的构造函数中注入服务:
export class AppComponent {
form: ControlGroup;
constructor(public validationService:ValidationService) {
...
}
}
Next, bind to the validation controls as you normally would, except use the ValidationService
to register and return the state validator:
接下来,像往常一样绑定到验证控件,除了使用ValidationService注册并返回状态验证器:
new Control('', validationService.register('required', Validators.required));
One of the great things about this solution is that you can easily compose and mix state validators with other built-in or custom validators:
此解决方案的一大优点是,您可以轻松地将状态验证器与其他内置或自定义验证器进行组合和混合:
this.form = new ControlGroup({
name: new Control('hello',
Validators.compose([
validationService.register('required', Validators.required),
validationService.register('minlength', Validators.minLength(4)),
Validators.maxLength(10)]))
});
Toggling the Validator
Use the service to toggle the state of the validator:
使用该服务切换验证器的状态:
validationService.toggle('required');
Here is an example of how to bind to the list of state validators in a table, and hookup the toggle function to a button click event:
下面是一个如何绑定到表中的状态验证器列表,并将toggle函数连接到按钮单击事件的示例:
<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>
演示Plnkr
#3
2
An alternative solution I use:
我使用的替代解决方案:
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
) { }
}
Use this directive on a html element to remove or add the required attribute:
在html元素上使用此指令可删除或添加必需属性:
<input [symToggleRequired]='FlagPropertyOfYourComponent'>
#1
29
For bound attributes to be removed they need to be set to null. There was a discussion to change it to remove on false but it was declined, at least for now.
对于要删除的绑定属性,需要将它们设置为null。有一个讨论要改变它以删除虚假,但它被拒绝,至少现在。
[required]="isRequired ? '' : null"
or
要么
[required]="isRequired ? 'required' : null"
Your Plunker produces an error because of missing []
around ngControl
.
由于在ngControl周围缺少[],您的Plunker会产生错误。
See also this Plunker for a working example
有关工作示例,请参阅此Plunker
See also Deilan's comments below.
另见Deilan的评论如下。
#2
5
It seems you already have an answer for adding/removing the readonly attribute. For the required attribute, I suggest creating a service to keep track of the enabled/disabled state of the validator, and then to leverage the service when binding to your validation controls.
您似乎已经有了添加/删除readonly属性的答案。对于required属性,我建议创建一个服务来跟踪验证器的启用/禁用状态,然后在绑定到验证控件时利用该服务。
State Validator
This class is responsible for keeping track of the validator and its enabled/disabled state.
该类负责跟踪验证器及其启用/禁用状态。
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;
}
}
}
It has methods to enable, disable, or toggle the validator; and also a get
method that returns a new validator function, which when invoked will call the underlying validator function if the validator is enabled, or return null when the validator is not enabled.
它具有启用,禁用或切换验证器的方法;还有一个get方法,它返回一个新的验证器函数,如果启用了验证器,它将在调用时调用底层验证器函数,或者在未启用验证器时返回null。
Validation Service
This class is a singleton service responsible for registering validators by key, and supporting methods to enable, disable, or toggle a validator based on that key.
此类是一个单件服务,负责按键注册验证器,以及支持基于该密钥启用,禁用或切换验证器的方法。
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;
}
}
The service also has a list
function for returning a list of key/value pairs where the key represents the registered validator key, and the value is a Boolean indicator that represents the validator's enabled state.
该服务还具有一个列表函数,用于返回键/值对列表,其中键表示已注册的验证器键,该值是表示验证器启用状态的布尔指示符。
Component
To use the ValidationService
, register the service with the root injector during bootstrap:
要使用ValidationService,请在引导期间使用根注入器注册服务:
bootstrap(AppComponent, [ValidationService]);
Or register the service with the component-level injector:
或者使用组件级注入器注册服务:
@Component({
selector: 'app',
providers: [ValidationService],
...
})
Then inject the service in your component's constructor:
然后在组件的构造函数中注入服务:
export class AppComponent {
form: ControlGroup;
constructor(public validationService:ValidationService) {
...
}
}
Next, bind to the validation controls as you normally would, except use the ValidationService
to register and return the state validator:
接下来,像往常一样绑定到验证控件,除了使用ValidationService注册并返回状态验证器:
new Control('', validationService.register('required', Validators.required));
One of the great things about this solution is that you can easily compose and mix state validators with other built-in or custom validators:
此解决方案的一大优点是,您可以轻松地将状态验证器与其他内置或自定义验证器进行组合和混合:
this.form = new ControlGroup({
name: new Control('hello',
Validators.compose([
validationService.register('required', Validators.required),
validationService.register('minlength', Validators.minLength(4)),
Validators.maxLength(10)]))
});
Toggling the Validator
Use the service to toggle the state of the validator:
使用该服务切换验证器的状态:
validationService.toggle('required');
Here is an example of how to bind to the list of state validators in a table, and hookup the toggle function to a button click event:
下面是一个如何绑定到表中的状态验证器列表,并将toggle函数连接到按钮单击事件的示例:
<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>
演示Plnkr
#3
2
An alternative solution I use:
我使用的替代解决方案:
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
) { }
}
Use this directive on a html element to remove or add the required attribute:
在html元素上使用此指令可删除或添加必需属性:
<input [symToggleRequired]='FlagPropertyOfYourComponent'>