【问题标题】:How do use a custom data type with ngModel in Angular Dart如何在 Angular Dart 中使用带有 ngModel 的自定义数据类型
【发布时间】:2018-07-27 22:57:10
【问题描述】:

我正在 AngularDart 中构建一个应用程序,到目前为止一切顺利。我特别喜欢它使表格变得多么容易。但是,我在这方面遇到了一些障碍。

基本上我想做的是让给定表单元素的 ngModel 使用不同的数据类型,根据需要在两者之间来回转换。例如,我在我的 HTML 中使用了 <input type='number'/> 元素,但在 dart 业务逻辑方面,我想将该值作为 Dart Decimal 类(来自这里:https://pub.dartlang.org/packages/decimal)来处理,因为我需要避免浮点问题。

我在我的应用程序中大量使用了 2-way 数据绑定和 ngModel,因为它非常棒并且非常适合这个应用程序。但是,ngModel 在这种特殊情况下不起作用。显然我可以解决它,但我希望更优雅一点。我希望能够指定一些允许我使用 ngModel 进行类型转换的类或函数。

我在 Google 和文档中四处查看,并怀疑我的解决方案与使用表单控件有关,尽管我对这究竟是如何工作的有点困惑。我很难找到与我正在尝试做的事情相关的示例代码或文档。也许我在那里叫错了树。

这是一个超级简化的示例,说明如果我能弄清楚我需要做什么,我希望能够完成什么:

@Component(
  selector: 'my-component',
  template: '...<input type="number" [(ngModel)]="thing.attr"/>...'
)
class MyComponent{

  DataObject thing = new DataObject();
}

class DataObject{
  Decimal attr;
}

我想这是我可能会遇到的很多情况,即需要进行类型转换,而不仅仅是在这种情况下使用 Decimal 类,因此任何人提供的任何帮助或建议都将不胜感激.


更新

根据下面 Ted Sander 的回答,我能够取得一些不错的进展,但它对我来说仍然不太有效,我不知道为什么。

这是我最终得到的代码:

import 'package:angular/angular.dart';
import 'dart:html';
import 'package:angular_forms/angular_forms.dart';

import 'package:decimal/decimal.dart';

@Directive(
  selector: 'input[type=decimal][ngControl],'
      'input[type=decimal][ngFormControl],'
      'input[type=decimal][ngModel]',
)
class DecimalValueAccessor implements ControlValueAccessor {
  final InputElement _element;

  DecimalValueAccessor(HtmlElement element) : _element = element as InputElement;

  @HostListener('change', ['\$event.target.value'])
  @HostListener('input', ['\$event.target.value'])
  void handleChange(String value) {
    print('About to parse decimal');
    Decimal dec;
    try{
      dec = new Decimal.parse(value);
    }
    catch (e){
      //TODO: mark feild as invalid
      return;
    }
    print('Got $dec with type ${dec.runtimeType}');
    onChange((value == '' ? null : dec), rawValue: value);
  }

  void writeValue(value) {
    _element.value = '$value';
  }

  void onDisabledChanged(bool isDisabled) {
    _element.disabled = isDisabled;
  }

  TouchFunction onTouched = () {};

  @HostListener('blur')
  void touchHandler() {
    onTouched();
  }

  /// Set the function to be called when the control receives a touch event.
  void registerOnTouched(TouchFunction fn) {
    onTouched = fn;
  }

  ChangeFunction<Decimal> onChange = (Decimal _, {String rawValue}) {};

  /// Set the function to be called when the control receives a change event.
  void registerOnChange(ChangeFunction<Decimal> fn) {
     onChange = fn;
  }
}

它似乎可以以一种方式工作:如果我以编程方式更改值,它似乎可以将其拾取并正常工作。但是,如果我通过输入更改它,则会引发异常Type 'String' is not a subtype of expected type 'Decimal'.

如您所见,我添加了一些打印语句,只是为了确保类型转换代码实际运行。正如我所料,它会打印出“About to parse decimal”和“Got 1.55 with type Decimal”。但是,我注意到这不是在控制台中抛出异常之前而是在之后显示的,这真的让我感到困惑。有没有人知道为什么会发生这种情况?

【问题讨论】:

  • 我没有看到提供者告诉表单系统它是一个 ControlValueAccessor:提供者:[ExistingProvider.forToken(ngValueAccessor,DecimalValueAccessor)],
  • 完美,添加该行使一切正常!告诉 Angular 它是一个 ControlValueAccessor 似乎是一种奇怪的方式,但是嘿,它有效,所以我很高兴。谢谢!

标签: angular dart angular-ngmodel angular-dart


【解决方案1】:

很好的问题。您正在寻找的是 ControlValueAccessor。它负责从 DOM 元素或组件中读取/写入/转换值。

可以看到 angular_forms 编号版本here

更复杂的 angular_component 版本是here

您将希望创建一个基本上可以执行 angular_forms 版本的功能,但不使用 double.parse。您创建的指令我建议给它一个 input[type=decimal] 选择器,这样它就不会与表单提供的指令冲突,并将该指令添加到您想要使用它的组件中的指令列表中。

很高兴你喜欢 AngularDart!

【讨论】:

  • 谢谢,这真的帮助我走上正轨。我想我仍然缺少一些东西。我已经用我当前的代码添加了一个更新。关于我做错了什么有什么想法吗?
  • 第二个链接失效
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-06-15
  • 2020-01-12
  • 1970-01-01
  • 1970-01-01
  • 2021-06-25
  • 1970-01-01
相关资源
最近更新 更多