Angular - 如何以百分比形式制作输入字段格式,但在编辑时删除百分比?

Posted

技术标签:

【中文标题】Angular - 如何以百分比形式制作输入字段格式,但在编辑时删除百分比?【英文标题】:Angular - How to make input field formated in percent but with percent removed when editing it? 【发布时间】:2018-04-21 12:26:34 【问题描述】:

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

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

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

该字段应该使用 ngModel 绑定。

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

到目前为止,我已经尝试了一些方法,但都没有解决所有问题。

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.transform() 相反的操作,例如类似 PercentPipe.parse() 的东西(不存在)。这将需要为您应该具有此行为的每个字段添加(焦点)事件处理程序。可重用性会很低。我相信角度指令方法应该是可取的。

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

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

我宁愿不必在 [ngModel] 中仍然使用“正常” PercentPipe,因为它需要编写 digitInfo 1.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' 这显然是用户要输入的)

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

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

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

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

或者应该采取其他方法?

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

【问题讨论】:

问题解决了吗? 【参考方案1】:

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

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

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

【讨论】:

这将是一个非常优雅的解决方案,如果它有效的话,哈哈 确实,非常优雅的解决方案。无论如何要使用 [ngModel]="myModel" 吗?我需要将 ngModel 分配给 #myModel="ngModel",以便检查 [ngClass]=" 'is-invalid': myModel.invalid "。或者,是否可以在不使用 ngModel 的情况下检查 myModel 是否无效?【参考方案2】:

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

假设您有一个管道可以转换 97.52 =&gt; 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 

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

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

这对你有用吗?

【讨论】:

嗨。感谢您的建议,但是如果我理解得很好,我认为这不会起作用。 您建议在组件级别有一个参数showFormatted,但是在我的组件中,我显示了一个包含多个&lt;input&gt; 的表格,并且每个&lt;input&gt; 必须是独立的(我不希望所有&lt;input&gt; 切换一次到编辑模式,即丢失百分比格式,只要我专注于一个 &lt;input&gt;,如果我有一个独特的参数 showFormatted,就会发生这种情况。 另外对于初始加载,我了解您建议将值从 0.9752 更改为 95.52;这是我每次使用要显示可编辑百分比值的输入字段时必须记住的事情。另外,每次我需要保存值时,它还需要执行 popsite 操作(并记住在我使用可编辑百分比值的每个场景中执行此操作)。【参考方案3】:

在你的指令中添加一个 ngOnInit

ngOnInit()

    this.htmlInputElement.value = this.parse(value);

【讨论】:

嗨。感谢您的回答。但是,组件级别的 ngOnInit() 不起作用,就像我在第 3 项中指出的那样),我不是在 ngOnInit(组件的,因此不是在指令的 ngOnInit),而是在后端响应之后(可观察/订阅)。所以在 ngOnInit 的时候,我还没有数据 我不探究,但在 blog.ngconsultant.io/… 你有一个你正在尝试做的例子

以上是关于Angular - 如何以百分比形式制作输入字段格式,但在编辑时删除百分比?的主要内容,如果未能解决你的问题,请参考以下文章

在Swift 4中输入文本字段时填充百分比的进度条

如何限制输入文本框仅以 Angular2 形式输入数字?

我有一种形式可以更新mysql中的某些值,当输入为空时,如何避免更新单元格?

以角度形式将输入创建为数组

求助excel制作图表高手 怎么制作双Y轴 也就是左边是百分比值 右边是数值?

订阅多个字段的 valueChanges 导致反应形式 angular 2 的性能问题