Angular 2 自定义复合控件

2024-01-09

我正在尝试为 Angular 2 创建一个自定义复合控件。我的要求是我需要创建一个允许用户选择文件的通用文件选择器控件either使用 html5 输入[类型=文件]or通过输入文件的 url。

我决定创建通用表单控件,为两个子控件实现 ControlValueAccessor 接口,因为它们将在其他地方单独使用。

我试图将它们都包裹在一个文件选择器本地或远程(因为缺乏更好的词)控制。该外部控件应该负责发出所选文件的内容,而不关心如何选择文件。

将价值一直传播到消费形式很容易。每次子控件将值传播到中间控件时,中间控件都会使用 registerChange 回调将其沿链进一步转发给使用者。

但是,我在传播子控件中可能发生的验证错误时遇到了麻烦。我需要将错误一直传播到消费表单,以便将它们本地化。

例如。如果用户在远程文件选择器子控件中输入无效的 url,则该子控件的验证函数将触发并显示正确的错误。该错误被交给中间控制。如何将此无效网址错误一直传播到使用表单?

更广泛地说,是否有关于如何在 Angular 2 中创建复合控件的具体指南?我找不到任何包装其他自定义控件的自定义控件的示例,因此我不确定我是否正确执行此操作。

换句话说,给出:

Form:

outerForm = new FormGroup({
    file: new FormControl(null, Validators.required)
});

<form [formGroup]="outerForm">
    <File-Picker-Local-Or-Remote formControlName="file"></File-Picker-Local-Or-Remote>
    <span class="error">******???******</span>
</form>

文件选择器本地或远程

innerForm = new FormGroup({
    local: new FormControl(),
    remote: new FormControl(null, Validators.pattern('http://...'))
});

<input type="file" formControlName="local" />
<input type="text" formControlName="remote" />

当远程子控件验证失败时,它会将其错误代码提供给innerForm。如何将这些错误消息传播到外部表单,以便我可以用适当的验证消息替换 ******???****** ?

编辑:我应该注意到,我有很多方法可以破解解决方案或绕过这个问题,包括使用事件发射器构建我自己的解决方案,首先不使用复合控件等。

我真正感兴趣的是角度2路创建可重用和可扩展的表单控件,消费者可以像任何其他表单控件一样与之交互,并且可以由其他开发人员进一步构建以创建更高级别的控件。


我和一位同事不久前就解决了这个问题,但这里是其他遇到这个问题的人的解决方案。

关键是在复合组件中实现 ControlValueAccessor 和 Validator 接口。

E.g.

Custom date控制,实现 ControlValueAccessor

@Component({
  ...
  providers: [{
    provide: NG_VALUE_ACCESSOR,
    useExisting: CustomDateControl),
    multi: true
  }]
})
export class CustomDateControl implements ControlValueAccessor {
  // implement ControlValueAccessor
}

Custom time控制,实现 ControlValueAccessor

@Component({
  ...
  providers: [{
    provide: NG_VALUE_ACCESSOR,
    useExisting: CustomTimeControl),
    multi: true
  }]
})
export class CustomTimeControl implements ControlValueAccessor {
  // implement ControlValueAccessor
}

自定义复合控件dateTime,实现 ControlValueAccessorand验证器

@Component({
  ...
  providers: [{
    provide: NG_VALIDATORS,
    useExisting: CustomDateTimeControl,
    multi: true
  }, {
    provide: NG_VALUE_ACCESSOR,
    useExisting: CustomDateTimeControl,
    multi: true
  }]
})
export class CustomDateTimeControl implements OnInit, ControlValueAccessor, Validator {
  private propagateChange = function (change) { };
  private propagateTouched = function () { };

  // Inner controls (you can also use an internal FormGroup for this)
  public date = new FormControl();
  public time = new FormControl();

  constructor() {}

  ngOnInit() {
    this.date.valueChanges
      .subscribe(value => {
        this.propagateChange(value + ' ' + this.time.value);
        this.propagateTouched();
      }

    this.time.valueChanges
      .subscribe(value => {
        this.propagateChange(this.date.value + ' ' + value);
        this.propagateTouched();
      }
    }

  writeValue(value) {
    // Need to update the inner controls, but don't use setValue / patchValue,
    // as that will trigger valueChanges in the above subscriptions,
    // incorrectly calling touched
  }

  registerOnChange(fn) {
    this.propagateChange = fn;
  }

  registerOnTouched(fn) {
    this.propagateTouched = fn;
  }

  validate(control) {
    // Custom logic to validate the parent control. In this case,
    // we may choose to union all childrens' errors.

    let errors = Object.assign(this.localControl.errors || {}, this.remoteControl.errors || {});
    return Object.keys(errors).length ? errors : null;
  }
}

对于我自己最初的问题的回答,将错误冒泡到复合控件链上的一个好方法是在这些复合控件中实现 Validator,并让它们的验证函数返回子控件错误的某种组合。

我希望这对其他人有用。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Angular 2 自定义复合控件 的相关文章

  • 显示具有多个父代的 D3 树

    我目前有this http bl ocks org mbostock 4339083图已实现 我希望在描述具有多个父节点的子节点时保持结构和可折叠性 有没有办法做到这一点 我研究了力图 但我也想保留一组层次结构 这意味着 1 级的父级可以有
  • angular2 MdDialog 未显示为弹出窗口

    所以我尝试使用 MdDialog 来显示错误消息 不幸的是 它不是显示为弹出窗口 而是显示为页面底部的块 我需要查看或更改哪些内容才能使其正常工作 下面的代码 common modal component html h2 title h2
  • 从函数返回函数的目的是什么?

    阅读一些遗留代码 发现 A prototype setSize function var v1 new Vector2 return function size var halfSize v1 copy size multiplyScala
  • .push() 将多个对象放入 JavaScript 数组中返回“未定义”

    当我将项目添加到beats数组然后console log用户时 我得到了数组中正确的项目数 但是当我检查 length 时 我总是得到 1 尝试调用索引总是会给我 未定义 如下所示 Tom beats 1 我想我错过了一些明显的东西 但这让
  • 使用 Node.js 构建网站的最佳实践

    这个问题的答案是社区努力 help privileges edit community wiki 编辑现有答案以改进这篇文章 目前不接受新的答案或互动 我想知道如何使用 Node js 从头开始 开发一个网站 我明白我怎么能possibly
  • 在版本 4.4.6 中禁用 ckeditor 上下文菜单

    我在 Rails4 项目中使用 ckeditor 我尝试了 ckeditor gem 和 ckeditor rails gem 来提供 ckeditor 库 这里有多个帖子 人们希望删除 ckeditor 上下文菜单 以便可以显示本机浏览器
  • 在指令中动态添加 *ngIf

    如何动态地将 ngIf 添加到用属性指令修饰的元素 为了一个简单的实验 我尝试了这个 Directive selector lhUserHasRights export class UserHasRightsDirective implem
  • 如何在网站上使用 svg 元素制作块的屏幕截图?

    我在网站上创建了一个构造函数 其本质是将所选元素及其颜色 svg中的元素 添加到访问者选择的背景和背景颜色 png中的背景 中 然后必须单击 保存 结果 按钮并仅执行工作区的屏幕截图 我写了这个脚本 但它需要屏幕截图 但只有背景 并忽略选定
  • 按下回车键时不刷新页面

    我遇到了一些问题 只要表单中有输入 回车键就会触发页面刷新 下面的代码 如果按下回车并且文本区域 input 中没有输入任何文本 则不会刷新页面 但是如果按下回车并且 input中有输入或者光标位于文本区域 我不确定是什么触发了它 因为 s
  • React Router v4 不渲染组件

    React Router v4 渲染组件存在问题 在应用程序初始加载时 它将呈现与 URL 相对应的正确组件 但是 任何后续的组件Link单击不会呈现所需的组件 图书馆 反应路由器 4 2 2 https reacttraining com
  • 模板解析:找不到管道

    我收到错误 模板解析错误 找不到管道 amDateFormat 这是我的app module ts import NgModule from angular core import MomentModule from angular2 mo
  • mongodb 聚合 - 累积字段的不同组值

    如果我有Player表格文件 name String score Int 我有Group文档 其中组代表玩家列表 groupName String players ObjectID 玩家可以属于多个组 我想做一个聚合Player文档 按以下
  • JavaScript eval("{}") 返回行为?

    根据ECMA 262 规范 http www ecma international org publications files ECMA ST Ecma 262 pdf 以下语句返回1 eval 1 eval 1 eval 1 var a
  • Vaadin 12 将对象传递给 JavaScript 函数:无法对类进行编码

    Vaadin 12 Kotlin 项目 In my myPage html我有JavaScript myObject redirectToCheckout sessionId 1111 2222 所以我需要调用javaScript函数red
  • 用于选择特定 div 中具有特定类的锚元素的 jQuery 选择器是什么

    我有一些这样的代码 我想选择每个 a 带有类的标签status在 div 中foo div a class status a div 你可以这样做 foo find status a
  • 如何使用 JavaScript 或 jQuery 克隆 HTML 元素的样式对象?

    我正在尝试克隆元素的样式对象 这应该允许我在更改后重置所述元素的样式 例如 el style left 50px curr style left 50px Modify the elements style The cloned style
  • 订阅内循环订阅?

    我目前正在与订阅内的 multiples forEach 订阅作斗争 我正在尝试检索对象列表 然后通过它们的 ID 检索它们的图像 目前我已经这样做了 this appTypeService get pipe map apps AppTyp
  • Rails 3.1+ 的 Jasmine 与 Mocha JavaScript 测试 [已关闭]

    Closed 这个问题是基于意见的 help closed questions 目前不接受答案 我对茉莉花有经验并且非常喜欢它 有谁有 Jasmine 和 Mocha 的经验 特别是 Rails 的经验吗 我想知道是否值得转用 我已经在 J
  • 什么是 WKWebView 中的 WKErrorDomain 错误 4

    fatal error LPWebView encounters an error Error Domain WKErrorDomain Code 4 A JavaScript exception occurred UserInfo 0x7
  • 使用velocity.js制作可拖动元素的动画

    我正在使用velocity js 为用户拖动的可拖动 SVG 元素设置动画 然而 velocity js 将先前的 mousemove 坐标排队并通过所有后续的 mousemove 坐标进行动画处理 我想要的是velocity js 不要对

随机推荐

  • 如何使用PHP7连接到sql服务器? (我错过了什么?)

    这是 phpinfo 输出 版本 php http cellcasehub com version php 这是代码 serverName X X X X connection array UID gt UserID PWD gt Pass
  • UnicodeDecodeError 'utf-8' 编解码器无法解码位置 2893 中的字节 0x92:无效的起始字节

    我正在尝试打开一系列 HTML 文件 以便使用 BeautifulSoup 从这些文件的正文中获取文本 我有大约 435 个文件想要运行 但我不断收到此错误 我尝试将 HTML 文件转换为文本并打开文本文件 但出现相同的错误 path Bi
  • Moq to Rhino - 假部分存储库

    我得到了这个非常酷的 Moq 方法 它伪造了我的 GetService 看起来像这样 private Mock
  • 在 jooq 的 UPDATE 中使用原始值表达式

    这是我试图执行的查询 UPDATE TABLE users SET metadata metadata keyA keyB WHERE
  • 如何在 R 中获取当前种子

    我正在 R 中运行一个带有随机因子的函数 我意识到我忘记运行set seed 在运行这个函数之前 有什么方法可以找回seedR 正在使用的值 我想它将是任意数字 但并不重要 以便我可以重现执行 您可以使用以下命令获取当前的随机状态 Rand
  • 如何将地址转换为纬度/经度?

    我如何将地址或城市转换为纬度 经度 我可以从哪些商业机构 租用 这项服务 这将用于具有全时互联网访问的 Windows PC 上的商业桌面应用程序 谷歌有一个地理编码 API 似乎对于他们拥有谷歌地图数据的大多数位置都运行良好 http g
  • 为什么内部 TABLE 部分必须经过 THEAD TFOOT TBODY 才能验证?

    我经常使用 THEAD TBODY 和 TFOOT 元素将数据表划分为可以使用 CSS 单独寻址的部分 我也明白总是有一个隐式的 TBODY 标签 让我困惑的是这些必须进入验证的顺序 该表将验证
  • Hadoop 映射器从 2 个不同的源输入文件读取

    我有一个链接很多映射器和缩减器的工具 在某些时候我需要合并之前映射缩减步骤的结果 例如作为输入 我有两个包含数据的文件 input a txt apple 10 orange 20 input b txt apple 5 orange 40
  • 如何使用javas Process.waitFor()?

    我正在尝试从 Java 运行命令行命令 快速的健全性检查让我意识到我遇到麻烦的原因是我无法获取pr waitFor 请拨打以下电话进行工作 该程序在不到 30 秒内结束 并且在 foo 之后不打印任何内容 我预计它会花费 30 多秒并在 f
  • 如何从模块导入类而不导入整个模块

    我有一个非常大的 python 模块 超过 1 GB 我使用以下命令在另一个 python 脚本中从该模块导入一个类from module import class 问题是 当我第一次启动 python 脚本时 内存消耗非常高 并且脚本执行
  • 具有多个手柄的 JQuery UI 滑块:如何阻止手柄交叉?

    我正在开发一个快速解决方案 它使用具有多个手柄的滑块来定义动态布局的宽度 我尝试使用 ExtJS3 和最新的 JQuery UI 在 ExtJS 中 您可以限制句柄 这样它们就不会相互交叉 这是一种实现我需要的 UI 的非常直观的方法 但是
  • 初始化集合时,哈希集对内存有何作用?

    我偶然发现了以下问题 我想要一个包含从 1 到 100 000 000 的所有数字的哈希集 我尝试了以下代码 var mySet new HashSet
  • ServiceStack OrmLite 命令超时

    使用 IDbConnection ExecuteSql 时如何设置命令超时 IDbConnection db ConnectionFactory OpenDbConnection db ExecuteSql 如果我使用 IDbCommand
  • 在撰写中禁用横向模式

    如何禁用可组合函数的横向模式 我想始终以纵向模式显示可组合项 PS 无法在活动的清单文件中设置它 因为我只希望此行为适用于一个可组合项 而不适用于活动中的其他可组合项 你可以这样做DisposableEffect 活动requestedOr
  • 线程:PyQt 因“出队时队列中存在未知请求”而崩溃

    我正在开发的应用程序的一部分需要向一小群人发送一些电子邮件 由于连接到 SMTP 服务器并发送电子邮件可能需要一些时间 因此我想在此操作期间使用后台线程来提供一个进度条来完成这项工作 现在发生的情况是 我可以实现一个工作得很好的测试结构 但
  • PHP 中如何判断 value 是否为日期

    我正在使用 PHP 中的值数组 其中一些值可能包括各种字符串格式的日期 我需要将多种格式的日期转换为它们的等效数字 Unix 时间戳 问题是能够确定字符串是否是日期 Using if timestamp strtotime str fals
  • Android:加密密码[重复]

    这个问题在这里已经有答案了 可能的重复 存储密码 https stackoverflow com questions 5359399 storing a password 我正在使用共享首选项来存储密码 按原样保存密码数据是否安全 或者我必
  • Three.js 中的渐进式加载/LOD/流网格

    我正在使用 STL 加载器将 stl 文件加载到 Three js 场景中 这些 stl 文件的大小从 5mb 到 50mb 不等 有没有一种方法可以用来在模型加载时逐步加载 流式传输 提高细节级别 不确定术语是否正确 以便我的用户在出现任
  • R 按组总和总结给出 NA

    我有一个像这样的数据框 Observations 2 190 835 Variables 13 patientid
  • Angular 2 自定义复合控件

    我正在尝试为 Angular 2 创建一个自定义复合控件 我的要求是我需要创建一个允许用户选择文件的通用文件选择器控件either使用 html5 输入 类型 文件 or通过输入文件的 url 我决定创建通用表单控件 为两个子控件实现 Co