草庐IT

javascript - 提交和值更改事件上的 Angular 4 ControlValueAccessor 值

coder 2024-07-20 原文

在我的 Angular (4 + Typescript) 项目中,我使用了已经准备好的组件(这并不重要,因为扩展 ControlValueAccessor 的方式是相同的,但如果这很重要,我使用了 ng2-select),因为更好用户体验和更好的外观。在将它包含到我看到的使用响应式(Reactive)表单的表单组件中之后,在提交时我返回(用于表单控件)基于类 SelectItem 的对象,该类在准备好的组件中使用,以管理选定的项目 - 如下所示:

// console.log(this.myForm.values)
Object {
    txtInput: 'value',
    // ...
    preparedComponent: SelectItem { // <--
        id: '1',
        text: 'Chosen item'
    }
}

因为该组件基本上只是标准选择控件的替代品,所以我期望我会取回以字符串形式形成的所选项目的 ID - 如下所示:

// console.log(this.myForm.values)
Object {
    txtInput: 'value',
    // ...
    preparedComponent: '1' // <--
}

在了解了 ControlValueAccessor 的实际含义及其工作原理之后,我将提交时返回的内容(或者更确切地说是项目更改时返回的方式 - onChange)更改为项目的 ID。问题解决了一段时间,直到我开始设置预定义值(在编辑实例上)以形成控件而不是空值(在添加实例上)。我发现这次 writeValue 正在根据作为预定义值发送给它的内容来分配值以形成控件。因此,如果我将预定义值发送为 ...

Object {
    id: '1',
    text: 'Chosen item'
}

...这也是 Object on submit 中的值,就像上面的第一个代码示例一样。我为此做了一个解决方法,在调用 writeValue 后立即使用 onChange 分配正确的值来控制。这确实是不正确的做法,但我想不出除此之外的任何事情:

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);
}

就我没有开始订阅表单控件的 valueChanges 而言,这也有效。问题在于,每次为准备好的组件分配预定义值时,即使使用 { emitEvent: false } ,提交后也会发出使用的值,返回给订阅者。

所以这就是我想用准备好的组件以某种方式处理的事情,因为我想在提交时从控件中获得正确的值,并且我不希望在值真的没有改变之前向订阅者发出更改,而不仅仅是被替换作为预定义值。任何想法如何处理这将不胜感激。

最佳答案

我不确定我是否理解正确,但我想试一试。

您希望组件的输入为以下类型:

{
    id: string,
    text: string
}   

但是您希望组件的输出 只是所选项目的字符串 ID。

我认为这个数据流有点尴尬。 During initialization, preparedComponent is an object, but when an item is selected you want to turn it into a string.除了类型安全问题之外,它感觉不直观。

为了比较,想象一下使用 ngModel 和文本输入来执行此操作:

<input type="text" [(ngModel)]="preparedComponent" />

您是否希望传入一个对象,并在用户键入时返回一个字符串?可能不是。


但是让我们假设由于某种原因它一定是这样的。您通过修改 ng2-selectControlValueAccessor 的实现,或者创建您自己的组件来实现 ControlValueAccessor 并包装 ng2-选择。 (我不知道你在你的问题中做了哪些)。现在您在选择一个项目时调用 this.onChange(val.id),这会使用字符串 ID 更新父组件。

然后您注意到一个单独的问题,即如果您预定义了一个选定值,ng2-select 会在初始化期间触发一个更改事件。这很奇怪,因为用户还没有与选择控件交互。因此,您尝试通过使用 emitEvent: false 在表单控件上调用 setValue 来初始化 preparedComponent,但我猜这是行不通的,因为虽然它可能在您初始化数据时阻止了更改事件的发生,ng2-select 立即对您的数据进行了第二次更改。

因此,您通过等到 ng2-select 的第一次更新将父组件更新为新对象来解决此问题,然后(使用 setTimeout)您用你真正想要的字符串 ID 覆盖它。这使 preparedComponent 与字符串保持同步,但并没有解决更改事件触发的问题,即使用户没有与控件交互也是如此。 (顺便说一句,如果你用自己的组件包装 ng2-select 那么我不确定你为什么必须做这个 setTimeout 部分,因为不会正如我在上一段中提到的,当 ng2-select 通知您一个新的选定项目时,您是否已经有另一个调用 this.onChange(val.id) 的函数? )


因为我不知道你是直接修改ng2-select,还是用你自己的组件包装它:

如果您正在修改 ng2-select,为什么不直接找到它的 writeValue 方法并删除发出事件的代码?这样它会在您预定义一个值时更新 DOM,但不会覆盖您的值。

如果你用你自己的组件包装 ng2-select,为什么不修改你的 writeValue 方法来存储一个标志 if ng2-select 即将触发一个事件,因此您可以忽略它:

private: ignoreSelectedEvent = false;

public writeValue(val: any): void {
    this.ignoreSelectedEvent = true;

    // Update ng2-select, which will cause an event to fire
}

然后在您对新选择的项目使用react的函数中:

if (this.ignoreSelectedEvent) {
    this.ignoreSelectedEvent = false;

    return;
}

// Update the model with the string ID

this.onChange(val.id);

关于javascript - 提交和值更改事件上的 Angular 4 ControlValueAccessor 值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43515028/

有关javascript - 提交和值更改事件上的 Angular 4 ControlValueAccessor 值的更多相关文章

  1. ruby-on-rails - date_field_tag,如何设置默认日期? [ rails 上的 ruby ] - 2

    我想设置一个默认日期,例如实际日期,我该如何设置?还有如何在组合框中设置默认值顺便问一下,date_field_tag和date_field之间有什么区别? 最佳答案 试试这个:将默认日期作为第二个参数传递。youcorrectlysetthedefaultvalueofcomboboxasshowninyourquestion. 关于ruby-on-rails-date_field_tag,如何设置默认日期?[rails上的ruby],我们在StackOverflow上找到一个类似的问

  2. ruby-on-rails - openshift 上的 rails 控制台 - 2

    我将我的Rails应用程序部署到OpenShift,它运行良好,但我无法在生产服务器上运行“Rails控制台”。它给了我这个错误。我该如何解决这个问题?我尝试更新ruby​​gems,但它也给出了权限被拒绝的错误,我也无法做到。railsc错误:Warning:You'reusingRubygems1.8.24withSpring.UpgradetoatleastRubygems2.1.0andrun`gempristine--all`forbetterstartupperformance./opt/rh/ruby193/root/usr/share/rubygems/rubygems

  3. ruby-on-rails - 相关表上的范围为 "WHERE ... LIKE" - 2

    我正在尝试从Postgresql表(table1)中获取数据,该表由另一个相关表(property)的字段(table2)过滤。在纯SQL中,我会这样编写查询:SELECT*FROMtable1JOINtable2USING(table2_id)WHEREtable2.propertyLIKE'query%'这工作正常:scope:my_scope,->(query){includes(:table2).where("table2.property":query)}但我真正需要的是使用LIKE运算符进行过滤,而不是严格相等。然而,这是行不通的:scope:my_scope,->(que

  4. ruby-on-rails - 事件管理员日期过滤器日期格式自定义 - 2

    是否有简单的方法来更改默认ISO格式(yyyy-mm-dd)的ActiveAdmin日期过滤器显示格式? 最佳答案 您可以像这样为日期选择器提供额外的选项,而不是覆盖js:=f.input:my_date,as::datepicker,datepicker_options:{dateFormat:"mm/dd/yy"} 关于ruby-on-rails-事件管理员日期过滤器日期格式自定义,我们在StackOverflow上找到一个类似的问题: https://s

  5. git使用常见问题(提交代码,合并冲突) - 2

    文章目录git常用命令(简介,详细参数往下看)Git提交代码步骤gitpullgitstatusgitaddgitcommitgitpushgit代码冲突合并问题方法一:放弃本地代码方法二:合并代码常用命令以及详细参数gitadd将文件添加到仓库:gitdiff比较文件异同gitlog查看历史记录gitreset代码回滚版本库相关操作远程仓库相关操作分支相关操作创建分支查看分支:gitbranch合并分支:gitmerge删除分支:gitbranch-ddev查看分支合并图:gitlog–graph–pretty=oneline–abbrev-commit撤消某次提交git用户名密码相关配置g

  6. ruby-on-rails - 事件记录 : Select max of limit - 2

    我正在尝试将以下SQL查询转换为ActiveRecord,它正在融化我的大脑。deletefromtablewhereid有什么想法吗?我想做的是限制表中的行数。所以,我想删除少于最近10个条目的所有内容。编辑:通过结合以下几个答案找到了解决方案。Temperature.where('id这给我留下了最新的10个条目。 最佳答案 从您的SQL来看,您似乎想要从表中删除前10条记录。我相信到目前为止的大多数答案都会如此。这里有两个额外的选择:基于MurifoX的版本:Table.where(:id=>Table.order(:id).

  7. ruby-on-rails - Ruby - 如何从 ruby​​ 上的 .pfx 文件中提取公钥、rsa 私钥和 CA key - 2

    我有一个.pfx格式的证书,我需要使用ruby​​提取公共(public)、私有(private)和CA证书。使用shell我可以这样做:#ExtractPublicKey(askforpassword)opensslpkcs12-infile.pfx-outfile_public.pem-clcerts-nokeys#ExtractCertificateAuthorityKey(askforpassword)opensslpkcs12-infile.pfx-outfile_ca.pem-cacerts-nokeys#ExtractPrivateKey(askforpassword)o

  8. ruby-on-rails - 使用 javascript 更改数据方法不会更改 ajax 调用用户的什么方法? - 2

    我遇到了一个非常奇怪的问题,我很难解决。在我看来,我有一个与data-remote="true"和data-method="delete"的链接。当我单击该链接时,我可以看到对我的Rails服务器的DELETE请求。返回的JS代码会更改此链接的属性,其中包括href和data-method。再次单击此链接后,我的服务器收到了对新href的请求,但使用的是旧的data-method,即使我已将其从DELETE到POST(它仍然发送一个DELETE请求)。但是,如果我刷新页面,HTML与"new"HTML相同(随返回的JS发生变化),但它实际上发送了正确的请求类型。这就是这个问题令我困惑的

  9. ruby-on-rails - 事件管理员和自定义方法 - 2

    这是我在ActiveAdmin中的自定义页面ActiveAdmin.register_page"Settings"doaction_itemdolink_to('Importprojects','settings/importprojects')endcontentdopara"Text"endcontrollerdodefimportprojectssystem"rakedataspider:import_projects_ninja"para"OK"endendend我想做的是,当我单击“导入项目”按钮时,我想在Controller中执行rake任务。但是我无法访问该方法。可能是什

  10. 带有 attr_accessor 的类上的 Ruby instance_eval - 2

    我了解instance_eval和class_eval之间的基本区别。我在玩弄时发现的是一些涉及attr_accessor的奇怪东西。这是一个例子:A=Class.newA.class_eval{attr_accessor:x}a=A.newa.x="x"a.x=>"x"#...expectedA.instance_eval{attr_accessor:y}A.y="y"=>NoMethodError:undefinedmethod`y='forA:Classa.y="y"=>"y"#WHATTT?这是怎么回事:instance_eval没有访问我们的A类(对象)然后它实际上将它添加到

随机推荐