目前我创建了两个项目指令。但是一个指令用于如果复选框被选中,我将得到 1,如果选中为 false,我将得到 0。另一个指令用于将值“1”转换为 1。
我只使用 TrueFalseValueDirective 几个复选框
实现目标的意图 格式化器和解析器 - NumberDirective Angular 中的“ng-true-value”和“ng-false-value”替代方案 - TrueFalseValueDirective
问题:
这两个指令都不起作用。任一指令都有效。我需要使两个指令可行
模板:
<form #f="ngForm">
<input type="checkbox" [(ngModel)]="data.option" name="options" checked="data.checked" trueFalseValue>
<select [(ngModel)]="data.selection" name="selection">
<option value="1">option 1</option>
<option value="2">option 2</option>
<option value="3">option 3</option>
</select>
<input type="text" name="Text1" [disabled]="data.selection!==1" [(ngModel)]="data.Text1" />
<input type="text" name="Text2" [disabled]="data.selection!==2" [(ngModel)]="data.Text2" />
<input type="text" name="Text3" [disabled]="data.selection!==3" [(ngModel)]="data.Text3" />
</form>
@Directive({
selector: '[ngModel]',
})
export class NumberDirective implements ControlValueAccessor {
onChange;
constructor( private renderer : Renderer2,
private element : ElementRef, public ngControl: NgControl ) {
if (ngControl) {
ngControl.valueAccessor = this;
}
}
@HostListener('input', [ '$event.target.value' ])
input( value ) {
this.onChange(parsrInt(value, 10);
}
writeValue( value : any ) : void {
const element = this.element.nativeElement;
this.renderer.setProperty(element, 'value', String(value));
}
registerOnChange( fn : any ) : void {
this.onChange = fn;
}
}
import {
Directive,
Input,
forwardRef,
HostListener,
ElementRef,
Renderer2
} from '@angular/core';
import {
ControlValueAccessor,
NgControl
} from '@angular/forms';
@Directive({
selector: 'trueFalseValue',
})
export class TrueFalseValueDirective implements ControlValueAccessor {
private propagateChange = (_: any) => {};
trueValue = 1; // some time true
falseValue = 0; // sometime true
constructor(private elementRef: ElementRef, private renderer: Renderer2, public ngControl: NgControl, ) {
if (ngControl) {
ngControl.valueAccessor = this;
}}
@HostListener('change', ['$event'])
onHostChange(ev) {
this.propagateChange(ev.target.checked ? this.trueValue : this.falseValue);
}
writeValue(obj: any): void {
if (obj === this.trueValue) {
this.renderer.setProperty(this.elementRef.nativeElement, 'checked', true);
} else {
this.renderer.setProperty(this.elementRef.nativeElement, 'checked', false);
}
}
registerOnChange(fn: any): void {
this.propagateChange = fn;
}
registerOnTouched(fn: any): void {}
setDisabledState?(isDisabled: boolean): void {}
}
参考网址:
这里有两种方法来解决这个问题,我更喜欢第一个选项,因为它适用于绑定数据和表单。
您采取的方法是部分正确的,因为写入值是模拟格式化程序和解析器的正确方法,但是您可以创建一个自定义的自定义方法,而不是弄乱内部角度
ngModel
指令,这可能会导致整个应用程序出现奇怪的错误可以执行相同功能的组件。
我创建了一个自定义表单字段,它将接受 true 和 false 值作为输入,并根据复选框选择来设置它们,这种方法似乎是最好的,唯一的缺点是您需要创建一个组件。
import {
Component,
Directive,
HostBinding,
HostListener,
Input,
Output,
EventEmitter,
} from '@angular/core';
import { bootstrapApplication } from '@angular/platform-browser';
import {
FormsModule,
NG_VALUE_ACCESSOR,
NgControl,
ControlValueAccessor,
} from '@angular/forms';
import { CommonModule } from '@angular/common';
@Component({
selector: 'app-true-false-value',
standalone: true,
template: `
<input type="checkbox" [checked]="_value === this.trueValue" (input)="valueChange($event)"/>
`,
providers: [
{
provide: NG_VALUE_ACCESSOR,
multi: true,
useExisting: TrueFalseValueComponent,
},
],
})
export class TrueFalseValueComponent implements ControlValueAccessor {
_value = 0;
@Input()
value: any;
onChange = (value: any) => {};
onTouched = () => {};
touched = false;
disabled = false;
@Input() trueValue: any = 1; // some time true
@Input() falseValue: any = 0; // sometime true
writeValue(value: number) {
this._value = value;
}
registerOnChange(onChange: any) {
this.onChange = onChange;
}
registerOnTouched(onTouched: any) {
this.onTouched = onTouched;
}
markAsTouched() {
if (!this.touched) {
this.onTouched();
this.touched = true;
}
}
setDisabledState(disabled: boolean) {
this.disabled = disabled;
}
valueChange(event: any) {
const value = event.target.checked;
this.markAsTouched();
this.onChange(value ? 'Y' : 'N');
}
}
@Component({
selector: 'app-root',
imports: [FormsModule, TrueFalseValueComponent, CommonModule],
standalone: true,
template: `
<form #f="ngForm">
<app-true-false-value name="options" [(ngModel)]="data.option" falseValue='N' trueValue='Y' trueFalseValue/>
<br/>
<select [(ngModel)]="data.selection" name="selection">
<option [ngValue]="1">option 1</option>
<option [ngValue]="2">option 2</option>
<option [ngValue]="3">option 3</option>
</select>
<br/>
<input type="text" name="Text1" [disabled]="data.selection!==1" [(ngModel)]="data.Text1" />
<input type="text" name="Text2" [disabled]="data.selection!==2" [(ngModel)]="data.Text2" />
<input type="text" name="Text3" [disabled]="data.selection!==3" [(ngModel)]="data.Text3" />
</form>
{{f.form.value | json}}
`,
})
export class App {
name = 'Angular';
data = {
option: 'Y',
selection: 1,
Text1: 'Text1',
Text2: 'Text2',
Text3: 'Text3',
};
}
bootstrapApplication(App);
AngularJS formatters and parsers
,部分被 Angular 的 getters and setters
取代。顾名思义,当访问值或设置值时会调用该方法。
如 stackblitz 中所示,此方法的问题在于,数据对象已完美更新,但表单未使用正确的值进行更新。
get optionTransformed() {
return this.data.option === 'Y';
}
set optionTransformed(value: boolean) {
this.data.option = value ? 'Y' : 'N';
}
在 HTML 上,我们将属性设置为
ngModel
,它既访问数据又设置数据,这里我们应用转换。
<input type="checkbox" name="options" [(ngModel)]="optionTransformed"/>
import { Component } from '@angular/core';
import { bootstrapApplication } from '@angular/platform-browser';
import { FormsModule } from '@angular/forms';
import { CommonModule } from '@angular/common';
@Component({
selector: 'app-root',
imports: [FormsModule, CommonModule],
standalone: true,
template: `
<form #f="ngForm">
<input type="checkbox" name="options" [(ngModel)]="optionTransformed"/>
<br/>
<select [(ngModel)]="data.selection" name="selection">
<option [ngValue]="1">option 1</option>
<option [ngValue]="2">option 2</option>
<option [ngValue]="3">option 3</option>
</select>
<br/>
<input type="text" name="Text1" [disabled]="data.selection!==1" [(ngModel)]="data.Text1" />
<input type="text" name="Text2" [disabled]="data.selection!==2" [(ngModel)]="data.Text2" />
<input type="text" name="Text3" [disabled]="data.selection!==3" [(ngModel)]="data.Text3" />
</form>
<br/>
<br/>
<br/>
Form:
<br/>
{{f.form.value | json}}
<br/>
<br/>
<br/>
<br/>
Data:
<br/>
{{data | json}}
`,
})
export class App {
name = 'Angular';
data = {
option: 'Y',
selection: 1,
Text1: 'Text1',
Text2: 'Text2',
Text3: 'Text3',
};
get optionTransformed() {
return this.data.option === 'Y';
}
set optionTransformed(value: boolean) {
this.data.option = value ? 'Y' : 'N';
}
}
bootstrapApplication(App);