如何在Angular Dart中将自定义数据类型与ngModel一起使用

时间:2018-07-27 22:57:10

标签: angular dart angular-ngmodel angular-dart

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

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

我在我的应用程序中大量使用了2路数据绑定和ngModel,因为它很棒并且可以很好地在此应用程序中使用。但是,ngModel在此特定情况下不起作用。显然,我可以解决这个问题,但是我希望有更多的优雅。我希望能够指定一些类或函数,让我可以使用ngModel进行类型转换。

我在Google和文档中四处浏览,怀疑我的解决方案与使用Form Control有关,尽管我对这到底是如何工作有些困惑。我很难找到与我想做的事情相关的示例代码或文档。也许我在那儿树错了树。

这是一个超级简化的示例,说明了如果我能确定需要做什么,我将能够完成的事情:

@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'.

我添加了一些打印语句,如您所见,只是为了确保类型转换代码正在实际运行。如我所料,它会打印出“关于解析十进制”和“具有小数类型的1.55”。但是,我注意到这不是在控制台之前出现的,而是在之后出现的,这确实使我感到困惑。有谁知道为什么会发生这种情况?

1 个答案:

答案 0 :(得分:4)

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

您可以看到angular_forms数字版本here

更复杂的angular_component版本是here

您将要创建其中的一个,基本上可以完成angular_forms版本,但不使用double.parse。我建议您创建的指令为它提供input[type=decimal]的选择器,以使其与表单提供的选择器不冲突,并将该指令添加到要使用它的组件中的指令列表中。

很高兴您到目前为止喜欢AngularDart!