@GZGavinZhao
Description
allow null values in a select and also allow customization of the comparison function
I made a custom CustomSelectControlValueAccessor to allow this, I think this can be integrated into AngularDart just like it was integrated into Angular typscript
angular/angular#10349
https://stackoverflow.com/questions/47477167/use-comparewith-function-from-angular-material-mat-select-component-with-linked
// ignore_for_file: unnecessary_import, implementation_imports
import 'dart:html';
import 'package:ngdart/angular.dart';
import 'package:ngforms/ngforms.dart';
import 'package:ngforms/src/directives/control_value_accessor.dart'
show ChangeHandler, ControlValueAccessor, ngValueAccessor, TouchHandler;
bool isPrimitive(val) {
return val is num || val is bool || val == null || val is String;
}
/// function for compare
bool _equals(Object? a, Object? b) {
return a == b;
}
String _buildValueString(String? id, Object? value) {
if (id == null) return '$value';
if (!isPrimitive(value)) value = 'Object';
var s = '$id: $value';
// TODO: Fix this magic maximum 50 characters (from TS-transpile).
if (s.length > 50) {
s = s.substring(0, 50);
}
return s;
}
String _extractId(String valueString) => valueString.split(':')[0];
const selectValueAccessorCustom = ExistingProvider.forToken(
ngValueAccessor,
CustomSelectControlValueAccessor,
);
/// The accessor for writing a value and listening to changes on a select
/// element.
///
/// Note: We have to listen to the 'change' event because 'input' events aren't
/// fired for selects in Firefox and IE:
/// https://bugzilla.mozilla.org/show_bug.cgi?id=1024350
/// https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/4660045
@Directive(
selector: 'select[ngControl],select[ngFormControl],select[ngModel]',
providers: [selectValueAccessorCustom],
// SelectControlValueAccessor must be visible to NgSelectOption.
visibility: Visibility.all,
)
class CustomSelectControlValueAccessor extends Object
with TouchHandler, ChangeHandler<dynamic>
implements ControlValueAccessor<Object?> {
final SelectElement _element;
Object? value;
final Map<String, Object?> _optionMap = <String, Object?>{};
num _idCounter = 0;
CustomSelectControlValueAccessor(HtmlElement element)
: _element = element as SelectElement;
@HostListener('change', ['\$event.target.value'])
void handleChange(String value) {
onChange(_getOptionValue(value), rawValue: value);
}
@override
void writeValue(Object? value) {
this.value = value;
var valueString = _buildValueString(_getOptionId(value), value);
_element.value = valueString;
}
@override
void onDisabledChanged(bool isDisabled) {
_element.disabled = isDisabled;
}
String _registerOption() => (_idCounter++).toString();
/// set custom function to Check whether two object references are to the same object.
@Input()
set compareWith(bool Function(Object? o1, Object? o2) fn) {
_compareWith = fn;
}
/// use equals (a == b) function for compare
@Input()
set useEquals(bool val) {
_compareWith = _equals;
}
/// use identical or custom function for compare
bool Function(Object? o1, Object? o2) _compareWith = identical;
String? _getOptionId(Object? value) {
for (var id in _optionMap.keys) {
//if (identical(_optionMap[id], value)) return id;
if (_compareWith(_optionMap[id], value)) return id;
}
return null;
}
/// allow null values in a select option
/// <option value="null" selected>Selecione</option>
/// <option ngValue="null" selected>Selecione</option>
@Input()
bool enableNullValue = false;
dynamic _getOptionValue(String valueString) {
final ngVal = _optionMap[_extractId(valueString)];
if (enableNullValue) {
return ngVal;
}
return ngVal ?? valueString;
}
}
/// Marks <option> as dynamic, so Angular can be notified when options change.
///
/// ### Example
///
/// <select ngControl="city">
/// <option *ngFor="let c of cities" [value]="c"></option>
/// </select>
@Directive(
selector: 'option',
)
class CustomNgSelectOption implements OnDestroy {
final OptionElement _element;
final CustomSelectControlValueAccessor? _select;
late final String id;
CustomNgSelectOption(HtmlElement element, @Optional() @Host() this._select)
: _element = element as OptionElement {
if (_select != null) id = _select!._registerOption();
}
@Input('ngValue')
set ngValue(Object? value) {
var select = _select;
if (select == null) return;
if (select.enableNullValue) {
select._optionMap[id] = value == 'null' ? null : value;
} else {
select._optionMap[id] = value;
}
_setElementValue(_buildValueString(id, value));
select.writeValue(select.value);
}
@Input('value')
set value(Object? value) {
var select = _select;
_setElementValue(value as String);
if (select != null) select.writeValue(select.value);
}
void _setElementValue(String value) {
_element.value = value;
}
@override
void ngOnDestroy() {
var select = _select;
if (select != null) {
select._optionMap.remove(id);
select.writeValue(select.value);
}
}
}
Please provide the steps to reproduce the bug
<div class="form-group col-md-2 mb-3">
<label class="form-label">Estado Civil:</label>
<select
class="form-select"
[(ngModel)]="matricula.candidato.estadoCivil"
ngControl="estadoCivil"
[enableNullValue]="true"
>
<option value="null" selected>Selecione</option>
<option
*ngFor="let estadoCivil of estadoCivilList "
[ngValue]="estadoCivil"
>
{{estadoCivil}}
</option>
</select>
</div>
Please provide the exception or error you saw
No response
Please provide the dependency environment you discovered this bug in (run dart pub deps -s compact)
Dart SDK version: 3.2.1 (stable) (Wed Nov 22 08:59:13 2023 +0000) on "windows_x64"
Anything else?
No response
@GZGavinZhao
Description
allow null values in a select and also allow customization of the comparison function
I made a custom CustomSelectControlValueAccessor to allow this, I think this can be integrated into AngularDart just like it was integrated into Angular typscript
angular/angular#10349
https://stackoverflow.com/questions/47477167/use-comparewith-function-from-angular-material-mat-select-component-with-linked
Please provide the steps to reproduce the bug
Please provide the exception or error you saw
No response
Please provide the dependency environment you discovered this bug in (run
dart pub deps -s compact)Anything else?
No response