use*_*255 8 javascript forms controls onchange angular
在我的Angular(4 + Typescript)项目中,我使用了已经准备好的组件(因为扩展ControlValueAccessor的方式是相同的,但是如果这很重要,我使用了ng2-select,这并不重要)因为更好的UX和更好的我想要的看.在将其包含到我使用的活动表单的表单组件中之后,在提交时,我回来(对于表单控件)对象基于在准备好的组件中使用的类SelectItem来管理所选项目 - 如下所示:
// console.log(this.myForm.values)
Object {
txtInput: 'value',
// ...
preparedComponent: SelectItem { // <--
id: '1',
text: 'Chosen item'
}
}
Run Code Online (Sandbox Code Playgroud)
由于该组件基本上只是标准选择控件的替代品,我期待我将获得一个形成为字符串的所选项的ID - 如下所示:
// console.log(this.myForm.values)
Object {
txtInput: 'value',
// ...
preparedComponent: '1' // <--
}
Run Code Online (Sandbox Code Playgroud)
在我了解了ControlValueAccessor实际上是什么以及它是如何工作之后,我改变了对项目onChangeID的提交(或更好地说项目更改 - )的方式.问题解决了一段时间,直到我开始设置预定义值(在编辑实例上)以形成控件而不是空值(在添加实例时).我发现这次writeValue是基于它作为预定义值发送到它的内容来分配值以形成控件.所以如果我发送预定义值为...
Object {
id: '1',
text: 'Chosen item'
}
Run Code Online (Sandbox Code Playgroud)
...这也是提交时Object中的值,就像上面的第一个代码示例一样.我为此做了一个解决方法,onChange在writeValue调用后立即为控件分配正确的值.这是非常不合适的方式,但除此之外我无法想出任何其他事情:
public writeValue(val: any): void {
this.selectedItems = val; // val is for example Object { id: '1', text: 'Chosen item' }
setTimeout(() => {
this.onChange(val.id); // just an example of emitted value, there should be some checks val is object and id exists in real code
}, 0);
}
Run Code Online (Sandbox Code Playgroud)
这也是我没有开始订阅表单控件的工作valueChanges.问题在于,每次为预先准备的组件分配预定义值时,在提交之后还会发出一个值,即使在使用时也会返回给订阅者{ emitEvent: false }.
所以这就是我想要以某种方式处理准备好的组件的事情,因为我希望从提交控件中获得正确的值,并且我不希望将更改发送给订阅者,直到值真的没有更改,而不仅仅替换为预定义值.任何想法如何处理这将是值得赞赏的.
我不确定我是否理解正确,但我想尝试一下。
您希望组件的输入具有以下类型:
{
id: string,
text: string
}
Run Code Online (Sandbox Code Playgroud)
但您希望组件的输出只是所选项目的字符串 ID。
我认为这个数据流有点尴尬。在初始化期间,preparedComponent是一个object,但是当选择一个项目时,您希望将其变成string。除了类型安全问题之外,它感觉不直观。
为了进行比较,想象一下使用ngModel文本输入来执行此操作:
<input type="text" [(ngModel)]="preparedComponent" />
Run Code Online (Sandbox Code Playgroud)
您是否希望传入一个对象,并在用户键入时返回一个字符串?可能不会。
但我们假设由于某种原因它一定是这样的。您可以修改 的ng2-select实现,或者创建您自己的实现和包装ControlValueAccessor组件。(我不知道你在问题中做了哪一个)。现在,您可以在选择某个项目时调用,这会使用字符串 ID 更新父组件。ControlValueAccessorng2-selectthis.onChange(val.id)
然后您注意到一个单独的问题,即如果ng2-select您预定义了选定的值,则会在初始化期间触发更改事件。这很奇怪,因为用户尚未与选择控件交互。因此,您尝试preparedComponent通过使用setValue调用表单控件来进行初始化emitEvent: false,但我猜这不起作用,因为虽然它可能会阻止在初始化数据时发出更改事件,但会ng2-select立即对数据进行第二次更改。
因此,您可以通过等待第一次更新将ng2-select父组件更新为新对象来解决此问题,然后(使用setTimeout)用您实际想要的字符串 ID 覆盖它。这可以使preparedComponent字符串保持最新状态,但即使用户未与控件交互,也无法解决更改事件触发的问题。(顺便说一句,如果您ng2-select使用自己的组件进行包装,那么我不确定为什么您必须执行此setTimeout部分,因为您是否已经有另一个函数this.onChange(val.id)在ng2-select通知您新选定的项目时调用,如我在上一段提到过?)
因为我无法判断您是ng2-select直接修改还是用您自己的组件包装它:
如果您正在修改ng2-select,为什么不直接找到它的writeValue方法并删除发出事件的代码呢?这样,当您预定义值时,它会更新 DOM,但不会覆盖您的值。
如果您ng2-select使用自己的组件进行包装,为什么不直接修改您的方法来存储即将触发事件的writeValue标志,以便您可以忽略它:ng2-select
private: ignoreSelectedEvent = false;
public writeValue(val: any): void {
this.ignoreSelectedEvent = true;
// Update ng2-select, which will cause an event to fire
}
Run Code Online (Sandbox Code Playgroud)
然后在对新选定项目做出反应的函数中:
if (this.ignoreSelectedEvent) {
this.ignoreSelectedEvent = false;
return;
}
// Update the model with the string ID
this.onChange(val.id);
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1481 次 |
| 最近记录: |