为自定义控件实现值访问器时,未从事件中的模型获取更新值
Posted
技术标签:
【中文标题】为自定义控件实现值访问器时,未从事件中的模型获取更新值【英文标题】:Not getting updated value from model in events when implementing value accessor for custom controls 【发布时间】:2016-09-12 13:35:33 【问题描述】:我正在关注下面的文章,我正在尝试在与 ngModel 和 ngControl 集成的 Angular 2 中实现自定义控件。
文章:http://almerosteyn.com/2016/04/linkup-custom-control-to-ngcontrol-ngmodel
但是我很难弄清楚在发出事件时如何获取更新的模型值。好像是在事件中使用更新前的模型。
这是一个带有示例的 plunker:
https://plnkr.co/edit/ixK6UxhhWZnkFyKfbgky
我做错了什么?
main.ts
import bootstrap from '@angular/platform-browser-dynamic';
import App from './app';
bootstrap(App, [])
.catch(err => console.error(err));
app.ts
import Component from '@angular/core'
import FORM_DIRECTIVES from "@angular/common";
import CustomInput from './custom-input.component'
@Component(
selector: 'my-app',
providers: [],
template: `
<form (ngSubmit)="onSave()" #demoForm="ngForm">
<div class="row info-row">
<span class="col-xs-12">
<p><span class="boldspan">Form data:</span>demoForm.value | json</p>
<p><span class="boldspan">Model data:</span> dataModel</p>
</span>
</div>
<custom-input ngControl="someValue" ref-input (onKeyDown)="onKeyDown(input)" [(ngModel)]="dataModel">Enter data:</custom-input>
</form>
`,
directives: [CustomInput, FORM_DIRECTIVES]
)
export class App
dataModel: string = '';
onKeyDown(event)
console.log(event._value);
console.log(this.dataModel);
custom-input.component.ts
import Component, Provider, forwardRef, Input, Output, EventEmitter from "@angular/core";
import ControlValueAccessor, NG_VALUE_ACCESSOR, CORE_DIRECTIVES from "@angular/common";
const noop = () => ;
const CUSTOM_INPUT_CONTROL_VALUE_ACCESSOR = new Provider(
NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => CustomInput),
multi: true
);
@Component(
selector: 'custom-input',
template: `
<div class="form-group">
<label><ng-content></ng-content>
<input class="form-control" [(ngModel)]="value" (keydown)="onKeyDownEvent($event)" (blur)="onTouched()">
</label>
</div>
`,
directives: [CORE_DIRECTIVES],
providers: [CUSTOM_INPUT_CONTROL_VALUE_ACCESSOR]
)
export class CustomInput implements ControlValueAccessor
@Output() onKeyDown: EventEmitter<any> = new EventEmitter();
//The internal data model
private _value: any = '';
//Placeholders for the callbacks
private _onTouchedCallback: (_:any) => void = noop;
private _onChangeCallback: (_:any) => void = noop;
//get accessor
get value(): any return this._value; ;
//set accessor including call the onchange callback
set value(v: any)
if (v !== this._value)
this._value = v;
this._onChangeCallback(v);
//Set touched on blur
onTouched()
this._onTouchedCallback();
//From ControlValueAccessor interface
writeValue(value: any)
this._value = value;
//From ControlValueAccessor interface
registerOnChange(fn: any)
this._onChangeCallback = fn;
//From ControlValueAccessor interface
registerOnTouched(fn: any)
this._onTouchedCallback = fn;
onKeyDownEvent(event)
this.onKeyDown.emit(event);
【问题讨论】:
【参考方案1】:我认为问题在于您将自定义输出和注册回调混合在一起。在这种情况下,不需要自定义输出。
您可以利用CustomInput
组件中的ngModelChange
事件来调用_onChangeCallback
回调:
@Component(
selector: 'custom-input',
template: `
<div class="form-group">
<label><ng-content></ng-content>
<input class="form-control" [(ngModel)]="value"
(ngModelChange)="onModelChange($event)"
(keydown)="onKeyDownEvent($event)"
(blur)="onTouched()">
</label>
</div>
`,
(...)
export class CustomInput implements ControlValueAccessor
(...)
onModelChange(value)
this.value = value;
this._onChangeCallback(value);
在这种情况下,不再需要您的 getter 和 setter。
您也可能对这篇文章感兴趣(“NgModel 兼容组件”部分):
http://restlet.com/blog/2016/02/17/implementing-angular2-forms-beyond-basics-part-2/【讨论】:
感谢您提供的信息。我不知道 ngModelChange 以及多么棒的文章。我已经尝试过你提出的建议,这里是一个新的plunkr,但奇怪的是,一旦我删除了 get 和 set,它就不再绑定初始值了。你说我把事情搞混了,但是如果不这样做,怎么可能在组件之外获取更新的模型呢?以上是关于为自定义控件实现值访问器时,未从事件中的模型获取更新值的主要内容,如果未能解决你的问题,请参考以下文章
在为自定义 DataGridViewColumn 设置属性时访问 DataGridView 控件