forked from angulardart/angular
-
Notifications
You must be signed in to change notification settings - Fork 15
Open
Labels
bugSomething isn't workingSomething isn't working
Description
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
ykmnkmi
Metadata
Metadata
Assignees
Labels
bugSomething isn't workingSomething isn't working