7

我正在尝试找到一种方法,在初始页面加载(通过角度服务将数据获取到后端,即可观察/订阅)时以百分比(例如 97,52%)显示 html 输入字段,但也有此输入当我编辑它时(即引发 DOM(焦点)事件时),字段会丢失它的百分比格式。

格式的数据绑定到模型。我们将模型字段称为 myModel.percentNumber,其中 percentNumber=1 表示“100 %”(0.69 表示“69 %”或再次为 100 表示“10 000 %”)

因此,当我单击指示“97,52 %”的字段时,我希望它变为“97.52”,但模型中的数据绑定值应该是 0.9752,因为这是我需要存储的。

该字段应该使用 ngModel 绑定。

注意:这应该适用于国际化,所以我不能使用基于删除空格、替换“。”的“脏”解决方案。by ',' ...在这里你可以看到我举了一个例子,其中格式化的百分比值应该有一个逗号作为小数分隔符和一个空格作为千​​位分隔符,但这取决于用户的本地化。

到目前为止,我已经尝试了一些东西,但没有一个能解决所有问题。

1)以2路绑定为起点,即

<input [(ngmodel)]="myModel.percentNumber | percent:'1.2-2'">

...但它确实会导致管道出现问题:

未捕获的错误:模板解析错误:

2)从我想要的2路绑定短语法到长语法,即

<input [ngmodel]="myModel.percentNumber | percent:'1.2-2'" (ngModelChange)="myModel.percentNumber = $event">

这允许在初始加载时以百分比形式具有正确的格式(在来自后端的响应中,如果 myModel.percentNumber=0.9752 它正确显示为 '97,52 %'),但是,当您单击输入进行编辑时它,当我希望它显示“97.52”时,格式会保持不变(),例如 PercentPipe.parse() 之类的东西(不存在)。这将需要为您应该具有此行为的每个字段添加(焦点)事件处理程序。可重用性会很低。我相信角度指令方法应该是可取的。

3) 使用角度指令:我创建了一个PercentFormatterDirective带有选择器的指令percentFormatter 和一个字符串类型的输入percentDigits,该输入将接受与 PercentPipe 相同的格式(即 digitInfo)。一个使用示例是:

<input percentFormatter percentDigits="1.2-2" [ngModel]="myModel.percentNumber" (ngModelChange)="myModel.percentNumber = $event">

我宁愿不必在 [ngModel] 中仍然使用“正常” PercentPipe,因为它需要编写 digitInfo1.2-2两次(即我不想写 <input percentFormatter percentDigits="1.2-2" [ngModel]="myModel.percentNumber | percent:'1.2-2'" (ngModelChange)="myModel.percentNumber = $event">

我可以在单击输入(焦点)时格式化值,正如我在 PercentFormatterDirective 中作为(焦点)事件的侦听器实现的那样:

  @HostListener("focus", ["$event.target.value"])
  onfocus(value) {
    if (value) {
      // we have to do the oposite than the transform (e.g. we want to go from % to number)
      this.htmlInputElement.value = this.parse(value);
    }
  }

因此,当我在该字段中单击时,这会从 '97,52 %' 到 '97.52' 得到满足。在这里,我不会详细介绍我创建的 parse() 方法(您只需要知道它是有效的,并且基于我用来获取用户本地化的 PercentPipe 和此查找是小数分隔符和千位分隔符)。

我还可以在离开输入字段时将值格式化为百分比格式,正如我在 PercentFormatterDirective 中作为 (blur) 事件的侦听器所实现的那样:

  @HostListener("blur", ["$event.target.value"])
  onblur(value) {
    if ((value as string).indexOf('%') === -1) {
      this.formatNumberInPercent('100for100percent');
    }
  }

所以当我离开现场时,这会从 '97.52' 到 '97,52 %' 得到满足。在这里,我不会详细介绍 formatNumberInPercent() 方法(您只需要知道它有效并且基于 PercentPipe.transform() 方法,但是在 PercentPipe.transform() 之前将值除以 100 会得到你从 '0.9752' 到 '97,52 %' 但在我的输入中我有 '97.52' 这显然是用户要输入的)

这个问题是在初始加载时(更确切地说,当通过 observable/subscribe 从后端返回时,当 myModel.percentNumber 设置时),来自 PercentFormatterDirective 的(焦点)或(模糊)@HostListener 都不会被称为没有与 DOM 的用户交互。如果我在 PercentFormatterDirective 中添加一个 ngOnInit(),那么是的,我可以格式化绑定值(即使用我创建的自定义方法将“0.9752”转换为“97,52 %”,该方法formatNumberInPercent('100for100percent')再次使用 PercentPipe.transform() 方法,但是不将值除以 100)...但是,如果我直接在组件中绑定数据,则此方法有效,ei 不使用可观察/订阅。当使用 observable/subscribe(我必须使用)从后端获取答案时,ngOnInit()PercentFormatterDirective 的已执行。

当获得响应(来自可观察/订阅)时,我需要能够执行格式化。我尝试添加ngOnChanges(changes: SimpleChanges)PercentFormatterDirective(然后用 读取 SimpleChange 的 de 数组for (let propName in changes)),但是我没有看到来自 myModel.percentNumber 的新绑定值。似乎ngOnChanges(changes: SimpleChanges)只提供了一个 SimpleChange 数组,其属性对应于我的指令输入(即 percentDigits)。

我已经private elementRef: ElementRef注入了指令的构造函数,但正如我所说的,ngOnChanges()我无法获得 myModel.percentNumber 的值(this.elementRef.nativeElement.value给我“”,从来没有任何值)。

也许我在生命周期中还为时过早?

或者也许应该采取另一种方法?

如果您有任何建议,我会很高兴听到它提出来!:)

4

3 回答 3

3

啊!与#2如此接近。您可以在模板中完成所有这些操作。您可以使用 [value] 将值设置为输入 - 然后使用 (input) - 或可能 (change) 将值转换回。我认为您不能在 ngModel 中使用管道:

<input type="number" [value]="myModel.percentNumber * 100" (input)="myModel.percentNumber = $event.target.value / 100">

也没有这种方式的文本转换或 dom 操作

于 2018-01-08T23:47:37.180 回答
0

只是一个思路,如果与你的思路相矛盾,请告诉我。

假设您有一个管道可以转换类似的东西97.52 => 97,52 %(或者您希望它在转换后看起来像)。它还接受“第二个参数”,这是boolean您格式化(97,52 %)或取消格式化(97.52)数据的基础。

// pipe's transform example
transform(value: any, showFormatted: boolean): string {
  if(showFormatted) { return <formatted-value>; // 97,52 % }
  else { return <unformatted-value>; // 97.52 }
}

现在,使用一个指令将第二个参数showFormatted(在组件内部初始化为trueor false,可能true在您的情况下)切换到管道,基于onFocusonBlur事件,如您的问题所示。因此,这将确保您的所有转换始终通过您拥有的“一个管道”,并且它本身要么绕过内容,要么根据其第二个参数对其进行转换。

现在的问题只是关于初始加载和最终保存方案。对于初始加载,如果您知道它进入的格式,那么只需将其本身转换为要提供给输入字段的值的“未格式化形式”。因此,例如,如果您知道它以 . 的形式出现0.9752,只需将其转换为97.52使用任何适用的js技术即可。这只是一次性的事情,因为后续交互将由管道和指令组合处理。然后在最后存储数据时,只需执行从97.52 %到 的反向转换0.9752

那对你有用吗?

于 2017-11-08T17:55:58.260 回答
0

在指令中添加 ngOnInit

ngOnInit()
{
    this.htmlInputElement.value = this.parse(value);
}
于 2017-11-08T19:37:11.870 回答