Angular11 在指令中访问模板驱动模型
Angular 11 Accessing template driven model in a directive
在 Angular 8.2 中,我有一个货币指令,可以为用户格式化货币字段,并且可以完美地工作:
<input [(ngModel)]="currentEmployment.monthlyIncome" currency>
@Directive({
selector: '[ngModel][currency]',
providers: [CurrencyPipe, NgModel],
})
export class CurrencyDirective implements OnDestroy {
// tracking
private focused: boolean = false;
private modelSubscription: Subscription;
// fraction size
@Input() size: number = 2;
// positive only
@Input() positiveOnly: boolean = false;
// model update
@Output() ngModelChange: EventEmitter<any> = new EventEmitter();
constructor(
private renderer: Renderer2,
private el: ElementRef,
private currencyPipe: CurrencyPipe,
private model: NgModel
) {
// set mobile keyboard to numpad
this.renderer.setAttribute(this.el.nativeElement, 'pattern', 'd*');
// input needs to be text when formatted
this.renderer.setAttribute(this.el.nativeElement, 'type', 'text');
// format when model is changed from somewhere else
this.modelSubscription = this.model.valueChanges.subscribe(value => {
// dont format while user is editing directly
if (!this.focused) {
this.setViewModel(this.currencyPipe.transform(value, this.size));
}
});
}
ngOnDestroy() {
// unsubscribe from model subscription
this.modelSubscription.unsubscribe();
}
@HostListener('focus')
focus() {
// user is editing, disable formating
this.focused = true;
// needs to be type number when unformatted
this.renderer.setAttribute(this.el.nativeElement, 'type', 'number');
// set the view model to raw data value
this.setViewModel(this.model.value);
// select all in input for easy editing
$(this.el.nativeElement)
.one('mouseup', event => {
event.preventDefault();
})
.select();
}
@HostListener('blur')
onBlur() {
// prepare model value
let newValue = Number(this.model.value);
// get absolute value if only positive values are allowed
if (this.positiveOnly) {
newValue = Math.abs(this.model.value);
}
// emit model change before clearing this.focused
this.ngModelChange.emit(newValue);
// input needs to be text when formatted
this.renderer.setAttribute(this.el.nativeElement, 'type', 'text');
// format view model
this.setViewModel(this.currencyPipe.transform(newValue, this.size));
// clear user focus
this.focused = false;
}
private setViewModel(value: any = null): void {
if (value !== null) {
this.el.nativeElement.value = value;
}
}
}
然而当更新到 Angular 11.2 我得到:
- 没有错误
- this.model.value 始终为空
- this.model.value更改。订阅永远不会触发
是否存在配置问题或模型现在工作方式不同?
原来我只需要从提供商那里删除 NgModel。 Angular 9 | ngModel Provider in Directive not working as expected
我不完全明白为什么它的工作方式不同,但这解决了它:
@Directive({
selector: '[ngModel][currency]',
providers: [CurrencyPipe],
})
export class CurrencyDirective implements OnDestroy {
// tracking
private focused: boolean = false;
private modelSubscription: Subscription;
// fraction size
@Input() size: number = 2;
// positive only
@Input() positiveOnly: boolean = false;
// model update
@Output() ngModelChange: EventEmitter<any> = new EventEmitter();
constructor(
private renderer: Renderer2,
private el: ElementRef,
private currencyPipe: CurrencyPipe,
private model: NgModel
) {
// set mobile keyboard to numpad
this.renderer.setAttribute(this.el.nativeElement, 'pattern', 'd*');
// input needs to be text when formatted
this.renderer.setAttribute(this.el.nativeElement, 'type', 'text');
// format when model is changed from somewhere else
this.modelSubscription = this.model.valueChanges.subscribe(value => {
// dont format while user is editing directly
if (!this.focused) {
this.setViewModel(this.currencyPipe.transform(value, this.size));
}
});
}
ngOnDestroy() {
// unsubscribe from model subscription
this.modelSubscription.unsubscribe();
}
@HostListener('focus')
focus() {
// user is editing, disable formating
this.focused = true;
// needs to be type number when unformatted
this.renderer.setAttribute(this.el.nativeElement, 'type', 'number');
// set the view model to raw data value
this.setViewModel(this.model.value);
// select all in input for easy editing
$(this.el.nativeElement)
.one('mouseup', event => {
event.preventDefault();
})
.select();
}
@HostListener('blur')
onBlur() {
// prepare model value
let newValue = Number(this.model.value);
// get absolute value if only positive values are allowed
if (this.positiveOnly) {
newValue = Math.abs(this.model.value);
}
// emit model change before clearing this.focused
this.ngModelChange.emit(newValue);
// input needs to be text when formatted
this.renderer.setAttribute(this.el.nativeElement, 'type', 'text');
// format view model
this.setViewModel(this.currencyPipe.transform(newValue, this.size));
// clear user focus
this.focused = false;
}
private setViewModel(value: any = null): void {
if (value !== null) {
this.el.nativeElement.value = value;
}
}
}
在 Angular 8.2 中,我有一个货币指令,可以为用户格式化货币字段,并且可以完美地工作:
<input [(ngModel)]="currentEmployment.monthlyIncome" currency>
@Directive({
selector: '[ngModel][currency]',
providers: [CurrencyPipe, NgModel],
})
export class CurrencyDirective implements OnDestroy {
// tracking
private focused: boolean = false;
private modelSubscription: Subscription;
// fraction size
@Input() size: number = 2;
// positive only
@Input() positiveOnly: boolean = false;
// model update
@Output() ngModelChange: EventEmitter<any> = new EventEmitter();
constructor(
private renderer: Renderer2,
private el: ElementRef,
private currencyPipe: CurrencyPipe,
private model: NgModel
) {
// set mobile keyboard to numpad
this.renderer.setAttribute(this.el.nativeElement, 'pattern', 'd*');
// input needs to be text when formatted
this.renderer.setAttribute(this.el.nativeElement, 'type', 'text');
// format when model is changed from somewhere else
this.modelSubscription = this.model.valueChanges.subscribe(value => {
// dont format while user is editing directly
if (!this.focused) {
this.setViewModel(this.currencyPipe.transform(value, this.size));
}
});
}
ngOnDestroy() {
// unsubscribe from model subscription
this.modelSubscription.unsubscribe();
}
@HostListener('focus')
focus() {
// user is editing, disable formating
this.focused = true;
// needs to be type number when unformatted
this.renderer.setAttribute(this.el.nativeElement, 'type', 'number');
// set the view model to raw data value
this.setViewModel(this.model.value);
// select all in input for easy editing
$(this.el.nativeElement)
.one('mouseup', event => {
event.preventDefault();
})
.select();
}
@HostListener('blur')
onBlur() {
// prepare model value
let newValue = Number(this.model.value);
// get absolute value if only positive values are allowed
if (this.positiveOnly) {
newValue = Math.abs(this.model.value);
}
// emit model change before clearing this.focused
this.ngModelChange.emit(newValue);
// input needs to be text when formatted
this.renderer.setAttribute(this.el.nativeElement, 'type', 'text');
// format view model
this.setViewModel(this.currencyPipe.transform(newValue, this.size));
// clear user focus
this.focused = false;
}
private setViewModel(value: any = null): void {
if (value !== null) {
this.el.nativeElement.value = value;
}
}
}
然而当更新到 Angular 11.2 我得到:
- 没有错误
- this.model.value 始终为空
- this.model.value更改。订阅永远不会触发
是否存在配置问题或模型现在工作方式不同?
原来我只需要从提供商那里删除 NgModel。 Angular 9 | ngModel Provider in Directive not working as expected
我不完全明白为什么它的工作方式不同,但这解决了它:
@Directive({
selector: '[ngModel][currency]',
providers: [CurrencyPipe],
})
export class CurrencyDirective implements OnDestroy {
// tracking
private focused: boolean = false;
private modelSubscription: Subscription;
// fraction size
@Input() size: number = 2;
// positive only
@Input() positiveOnly: boolean = false;
// model update
@Output() ngModelChange: EventEmitter<any> = new EventEmitter();
constructor(
private renderer: Renderer2,
private el: ElementRef,
private currencyPipe: CurrencyPipe,
private model: NgModel
) {
// set mobile keyboard to numpad
this.renderer.setAttribute(this.el.nativeElement, 'pattern', 'd*');
// input needs to be text when formatted
this.renderer.setAttribute(this.el.nativeElement, 'type', 'text');
// format when model is changed from somewhere else
this.modelSubscription = this.model.valueChanges.subscribe(value => {
// dont format while user is editing directly
if (!this.focused) {
this.setViewModel(this.currencyPipe.transform(value, this.size));
}
});
}
ngOnDestroy() {
// unsubscribe from model subscription
this.modelSubscription.unsubscribe();
}
@HostListener('focus')
focus() {
// user is editing, disable formating
this.focused = true;
// needs to be type number when unformatted
this.renderer.setAttribute(this.el.nativeElement, 'type', 'number');
// set the view model to raw data value
this.setViewModel(this.model.value);
// select all in input for easy editing
$(this.el.nativeElement)
.one('mouseup', event => {
event.preventDefault();
})
.select();
}
@HostListener('blur')
onBlur() {
// prepare model value
let newValue = Number(this.model.value);
// get absolute value if only positive values are allowed
if (this.positiveOnly) {
newValue = Math.abs(this.model.value);
}
// emit model change before clearing this.focused
this.ngModelChange.emit(newValue);
// input needs to be text when formatted
this.renderer.setAttribute(this.el.nativeElement, 'type', 'text');
// format view model
this.setViewModel(this.currencyPipe.transform(newValue, this.size));
// clear user focus
this.focused = false;
}
private setViewModel(value: any = null): void {
if (value !== null) {
this.el.nativeElement.value = value;
}
}
}