Skip to content

Commit

Permalink
Merge pull request #77 from netglade/fix/76-ondepedency-change
Browse files Browse the repository at this point in the history
Fix onDependencyChange logic
  • Loading branch information
petrnymsa authored Jan 10, 2025
2 parents 588c80e + 3704de7 commit 354e692
Show file tree
Hide file tree
Showing 7 changed files with 116 additions and 7 deletions.
6 changes: 6 additions & 0 deletions glade_forms/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# 3.0.1
- **[Fix]**: GladeFormProvider is missing key property [Fix 73](https://github.com/netglade/glade_forms/issues/73)
- **[Fix]**: enable value transform with text editing controller [Fix 72](https://github.com/netglade/glade_forms/issues/72)
- **[Fix]**: Input subscribed to its own changes in onDependencyChange [Fix 76](https://github.com/netglade/glade_forms/issues/76)


## 3.0.0

**Breaking release**

- **[Add]**: Add `allowBlank` parameter to `isEmpty` string validator.
Expand Down
5 changes: 5 additions & 0 deletions glade_forms/lib/src/core/glade_input.dart
Original file line number Diff line number Diff line change
Expand Up @@ -628,6 +628,11 @@ class GladeInput<T> {
_textEditingController?.removeListener(_onTextControllerChange);
}

@override
String toString() {
return '$inputKey ($value)';
}

void _syncValueWithController(T value, {required bool shouldTriggerOnChange}) {
final converter = stringToValueConverter ?? _defaultConverter;
try {
Expand Down
5 changes: 3 additions & 2 deletions glade_forms/lib/src/model/glade_model.dart
Original file line number Diff line number Diff line change
Expand Up @@ -122,9 +122,10 @@ abstract class GladeModel extends ChangeNotifier {
}

void notifyDependencies() {
final updatedKeys = _lastUpdates.map((e) => e.inputKey);
final updatedKeys = _lastUpdates.map((e) => e.inputKey).toSet();
for (final input in inputs) {
final union = input.dependencies.map((e) => e.inputKey).toSet().union(updatedKeys.toSet());
final updatedKeysExceptInputItself = updatedKeys.difference({input.inputKey});
final union = input.dependencies.map((e) => e.inputKey).toSet().intersection(updatedKeysExceptInputItself);

if (union.isNotEmpty) input.onDependencyChange?.call(union.toList());
}
Expand Down
2 changes: 1 addition & 1 deletion glade_forms/pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: glade_forms
description: A universal way to define form validators with support of translations.
version: 3.0.0
version: 3.0.1
repository: https://github.com/netglade/glade_forms
issue_tracker: https://github.com/netglade/glade_forms/issues
screenshots:
Expand Down
88 changes: 88 additions & 0 deletions glade_forms/test/model/glade_model_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
// ignore_for_file: avoid-duplicate-test-assertions, prefer-correct-callback-field-name, avoid-global-state

import 'package:glade_forms/glade_forms.dart';
import 'package:test/test.dart';

class _ModeWithDependencies extends GladeModel {
late GladeInput<int> a;
late GladeInput<int> b;
late GladeInput<int> c;

int aUpdated = 0;
int bUpdated = 0;
int cUpdated = 0;

int onDepenencyCalledCount = 0;

List<String> updatedDependencyKeys = [];

@override
List<GladeInput<Object?>> get inputs => [a, b, c];

@override
void initialize() {
a = GladeInput.intInput(value: 0, inputKey: 'a');
b = GladeInput.intInput(value: 1, inputKey: 'b');
c = GladeInput.intInput(
value: 1,
inputKey: 'c',
dependencies: () => [a, b],
onDependencyChange: (keys) {
if (keys.contains('a')) aUpdated++;
if (keys.contains('b')) bUpdated++;

onDepenencyCalledCount++;

updatedDependencyKeys = keys;
},
);

super.initialize();
}
}

void main() {
test('When updating [a] onDependencyChange is called for a', () {
final model = _ModeWithDependencies();

model.a.value = 5;
expect(model.a.value, equals(5));
expect(model.onDepenencyCalledCount, equals(1));
expect(model.lastUpdatedInputKeys, equals(['a']));
expect(model.updatedDependencyKeys, equals(['a']));
});

test('When updating [b] onDependencyChange is called for b', () {
final model = _ModeWithDependencies();

model.b.value = 5;
expect(model.b.value, equals(5));
expect(model.onDepenencyCalledCount, equals(1));
expect(model.lastUpdatedInputKeys, equals(['b']));
expect(model.updatedDependencyKeys, equals(['b']));
});

test('When updating [a, b] together onDependencyChange is called for [a,b]', () {
final model = _ModeWithDependencies();
model.groupEdit(() {
model.b.value = 5;
model.a.value = 5;
});

expect(model.a.value, equals(5));
expect(model.b.value, equals(5));
expect(model.onDepenencyCalledCount, equals(1));
expect(model.lastUpdatedInputKeys.toSet().difference({'a', 'b'}), equals(<String>{}));
expect(model.updatedDependencyKeys.toSet().difference({'a', 'b'}), equals(<String>{}));
});

test('When updating [c] onDependencyChange is not called', () {
final model = _ModeWithDependencies();
model.c.value = 5;

expect(model.c.value, equals(5));
expect(model.lastUpdatedInputKeys.toSet().difference({'c'}), equals(<String>{}));
expect(model.onDepenencyCalledCount, isZero);
expect(model.updatedDependencyKeys.toSet().difference({}), equals(<String>{}));
});
}
2 changes: 2 additions & 0 deletions glade_forms/test/model/group_edit_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,11 @@ class _ModeWithDependencies extends GladeModel {
c = GladeInput.intInput(
value: 1,
inputKey: 'c',
dependencies: () => [a, b],
onDependencyChange: (keys) {
if (keys.contains('a')) aUpdated++;
if (keys.contains('b')) bUpdated++;
if (keys.contains('c')) cUpdated++;

onDepenencyCalledCount++;
},
Expand Down
15 changes: 11 additions & 4 deletions storybook/lib/usecases/onchange/two_way_checkbox_change.dart
Original file line number Diff line number Diff line change
Expand Up @@ -51,19 +51,26 @@ class AgeRestrictedModel extends GladeModel {

return devMessage;
},
onChange: (info) {
vipInput.value = info.value >= 18;
},
// * cyclic dependency between ageInput and vipInput
// Better to use onDependencyChange inside vipInput
// onChange: (info) {
// vipInput.value = info.value >= 18;
// },
useTextEditingController: true,
);
vipInput = GladeInput.create(
validator: (v) => (v..notNull()).build(),
value: false,
inputKey: 'vip-input',
dependencies: () => [ageInput],
onDependencyChange: (updateInputKeys) {
if (updateInputKeys.contains('age-input')) {
vipInput.updateValue(ageInput.value >= 18, shouldTriggerOnChange: false);
}
},
onChange: (info) {
if (info.value && ageInput.value < 18) {
ageInput.value = 18;
ageInput.updateValue(18, shouldTriggerOnChange: false);
}
},
);
Expand Down

0 comments on commit 354e692

Please sign in to comment.