Integrate internal changes * Remove unnecessary type cast * Fix ObservableMap to notify on all mutations (issue #91) PiperOrigin-RevId: 413202846
diff --git a/CHANGELOG.md b/CHANGELOG.md index 4ec2494..f1c8c44 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md
@@ -1,6 +1,7 @@ ## 0.24.0-dev * Migrate to [null safety](https://dart.dev/null-safety). +* Update ObservableMap to notify observers about changes for all methods. ## 0.23.0
diff --git a/lib/src/observable_list.dart b/lib/src/observable_list.dart index c25534f..85c34ef 100644 --- a/lib/src/observable_list.dart +++ b/lib/src/observable_list.dart
@@ -244,7 +244,6 @@ // We are modifying the length just below these checks. Without the checks // Array.copy could throw an exception, leaving the list in a bad state // (with a length that has been increased, but without a new element). - if (index is! int) throw ArgumentError(index); RangeError.checkValidIndex(index, this); _list // Increase the length by adding [element], in case [E] isn't nullable.
diff --git a/lib/src/observable_map.dart b/lib/src/observable_map.dart index ec256f7..05f2a4f 100644 --- a/lib/src/observable_map.dart +++ b/lib/src/observable_map.dart
@@ -190,7 +190,9 @@ @override void addEntries(Iterable<MapEntry<K, V>> entries) { - _map.addEntries(entries); + for (var entry in entries) { + this[entry.key] = entry.value; + } } @override @@ -200,15 +202,21 @@ @override V update(K key, V Function(V value) update, {V Function()? ifAbsent}) { - return _map.update(key, update, ifAbsent: ifAbsent); + var value = containsKey(key) ? update(this[key] as V) : ifAbsent!(); + return this[key] = value; } @override - void updateAll(V Function(K key, V value) update) => _map.updateAll(update); + void updateAll(V Function(K key, V value) update) { + for (var key in keys) { + this[key] = update(key, this[key] as V); + } + } @override - void removeWhere(bool Function(K key, V value) test) => - _map.removeWhere(test); + void removeWhere(bool Function(K key, V value) test) { + keys.where((key) => test(key, this[key] as V)).toList().forEach(remove); + } // Note: we don't really have a reasonable old/new value to use here. // But this should fix "keys" and "values" in templates with minimal overhead.
diff --git a/test/observable_map_test.dart b/test/observable_map_test.dart index 5743001..b980983 100644 --- a/test/observable_map_test.dart +++ b/test/observable_map_test.dart
@@ -86,7 +86,7 @@ }); group('observe item', () { - late ObservableMap map; + late ObservableMap<String, int?> map; List<ChangeRecord>? changes; setUp(() { @@ -177,6 +177,48 @@ ]); }); }); + + test('change the item as part of addAll', () { + map.addAll({'b': 13, 'd': 4}); + expect(map, {'a': 1, 'b': 13, 'c': 3, 'd': 4}); + return Future(() { + expect(changes, [_changeKey('b', 2, 13)]); + }); + }); + + test('change the item as part of addEntries', () { + map.addEntries( + [MapEntry<String, int>('b', 13), MapEntry<String, int>('d', 4)]); + expect(map, {'a': 1, 'b': 13, 'c': 3, 'd': 4}); + return Future(() { + expect(changes, [_changeKey('b', 2, 13)]); + }); + }); + + test('update the item', () { + map.update('b', (int? value) => value == null ? value : value + 1); + expect(map, {'a': 1, 'b': 3, 'c': 3}); + return Future(() { + expect(changes, [_changeKey('b', 2, 3)]); + }); + }); + + test('update all items', () { + map.updateAll( + (String key, int? value) => value == null ? value : value + 1); + expect(map, {'a': 2, 'b': 3, 'c': 4}); + return Future(() { + expect(changes, [_changeKey('b', 2, 3)]); + }); + }); + + test('remove the item as part of removeWhere', () { + map.removeWhere((key, value) => value != null && value > 1); + expect(map, {'a': 1}); + return Future(() { + expect(changes, [_removeKey('b', 2)]); + }); + }); }); test('toString', () {