如何在 Angular Dart 中使用带有 ngModel 的自定义数据类型
How do use a custom data type with ngModel in Angular Dart
我正在使用 AngularDart 构建一个应用程序,到目前为止一切顺利。我特别喜欢它制作表格的简单程度。但是,我 运行 在这方面遇到了一些小问题。
基本上我想要做的是让给定表单元素的 ngModel 使用不同的数据类型,根据需要在两者之间来回转换。例如,我在 HTML 中使用 <input type='number'/>
元素,但在 Dart 业务逻辑方面,我想将该值作为 Dart Decimal
class(来自这里:https://pub.dartlang.org/packages/decimal)因为我需要避免浮点问题。
我在我的应用程序中广泛使用了 2 向数据绑定和 ngModel,因为它非常棒并且适用于此应用程序。但是,ngModel 在这种特殊情况下不起作用。显然我可以解决它,但我希望更优雅一点。我希望能够指定一些 class 或允许我使用 ngModel 进行类型转换的函数。
我查看了 Google 和文档,怀疑我的解决方案与使用表单控件有关,尽管我对它的工作原理有点困惑。我很难找到与我正在尝试做的事情相关的示例代码或文档。可能我找错树了。
这是一个超级简化的例子,说明如果我能弄清楚我需要做什么,我希望能够完成的事情:
@Component(
selector: 'my-component',
template: '...<input type="number" [(ngModel)]="thing.attr"/>...'
)
class MyComponent{
DataObject thing = new DataObject();
}
class DataObject{
Decimal attr;
}
我想这是我可能 运行 需要进行类型转换的事情,而不仅仅是在这种情况下 Decimal
class , 所以任何人的任何帮助或建议都将不胜感激。
更新
根据下面 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'.
如您所见,我添加了一些打印语句,只是为了确保类型转换代码实际上是 运行ning。正如我所料,它打印出“即将解析十进制”和“得到 1.55 类型的十进制”。但是,我注意到这不是之前出现的,而是 之后 异常在控制台中抛出,这让我很困惑。有没有人知道为什么会发生这种情况?
问得好。您正在寻找的东西是 ControlValueAccessor。它负责来自 DOM 元素或组件的 reading/writing/converting 值。
可以看到angular_forms号版本here.
更复杂的 angular_component 版本是 here。
您需要创建其中一个基本上可以执行 angular_forms 版本的操作,但不使用 double.parse
。您创建的指令我建议给它一个 input[type=decimal]
选择器,这样它就不会与表单提供的选择器冲突,并将该指令添加到您要使用它的组件中的指令列表中。
很高兴您到目前为止喜欢 AngularDart!
我正在使用 AngularDart 构建一个应用程序,到目前为止一切顺利。我特别喜欢它制作表格的简单程度。但是,我 运行 在这方面遇到了一些小问题。
基本上我想要做的是让给定表单元素的 ngModel 使用不同的数据类型,根据需要在两者之间来回转换。例如,我在 HTML 中使用 <input type='number'/>
元素,但在 Dart 业务逻辑方面,我想将该值作为 Dart Decimal
class(来自这里:https://pub.dartlang.org/packages/decimal)因为我需要避免浮点问题。
我在我的应用程序中广泛使用了 2 向数据绑定和 ngModel,因为它非常棒并且适用于此应用程序。但是,ngModel 在这种特殊情况下不起作用。显然我可以解决它,但我希望更优雅一点。我希望能够指定一些 class 或允许我使用 ngModel 进行类型转换的函数。
我查看了 Google 和文档,怀疑我的解决方案与使用表单控件有关,尽管我对它的工作原理有点困惑。我很难找到与我正在尝试做的事情相关的示例代码或文档。可能我找错树了。
这是一个超级简化的例子,说明如果我能弄清楚我需要做什么,我希望能够完成的事情:
@Component(
selector: 'my-component',
template: '...<input type="number" [(ngModel)]="thing.attr"/>...'
)
class MyComponent{
DataObject thing = new DataObject();
}
class DataObject{
Decimal attr;
}
我想这是我可能 运行 需要进行类型转换的事情,而不仅仅是在这种情况下 Decimal
class , 所以任何人的任何帮助或建议都将不胜感激。
更新
根据下面 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'.
如您所见,我添加了一些打印语句,只是为了确保类型转换代码实际上是 运行ning。正如我所料,它打印出“即将解析十进制”和“得到 1.55 类型的十进制”。但是,我注意到这不是之前出现的,而是 之后 异常在控制台中抛出,这让我很困惑。有没有人知道为什么会发生这种情况?
问得好。您正在寻找的东西是 ControlValueAccessor。它负责来自 DOM 元素或组件的 reading/writing/converting 值。
可以看到angular_forms号版本here.
更复杂的 angular_component 版本是 here。
您需要创建其中一个基本上可以执行 angular_forms 版本的操作,但不使用 double.parse
。您创建的指令我建议给它一个 input[type=decimal]
选择器,这样它就不会与表单提供的选择器冲突,并将该指令添加到您要使用它的组件中的指令列表中。
很高兴您到目前为止喜欢 AngularDart!