Conditions
Conditions control the visibility and enabled state of properties reactively. When a dependent property value changes, conditions are re-evaluated automatically by the PropertyCollection.
How Conditions Work
Each Property<T> can have two conditions:
visibleCondition-- controls whether the property is shown in the editorenabledCondition-- controls whether the property is editable
b.integer('capacity', 'Max Capacity',
defaultValue: 30,
visibleCondition: PropertyCollectionBuilder.whenTrue('enrollmentOpen'),
enabledCondition: PropertyCollectionBuilder.whenNot<String>('status', 'archived'),
);Evaluation Pipeline
- Each condition declares its
dependencies-- the property keys it depends on PropertyCollectionbuilds a reverse dependency map:dependency → {dependent properties}- When
FormGroup.valueChangesfires, the collection finds all affected properties - Each affected property's conditions are re-evaluated via
condition.evaluate(collection) - Visibility updates via
ValueNotifier<bool>(triggersValueListenableBuilderin the editor) - Enabled state updates via
PropertyControl.markAsEnabled()/markAsDisabled()
Condition Types
There are 12 built-in condition types.
EqualsCondition<T>
True when a property equals a specific value.
EqualsCondition<String>('status', 'active')
// Builder shorthand
PropertyCollectionBuilder.when<String>('status', 'active')NotEqualsCondition<T>
True when a property does not equal a specific value.
NotEqualsCondition<String>('status', 'archived')
// Builder shorthand
PropertyCollectionBuilder.whenNot<String>('status', 'archived')InCondition<T>
True when a property value is in a set of allowed values.
InCondition<String>('level', {'intermediate', 'advanced'})
// Builder shorthand
PropertyCollectionBuilder.whenIn<String>('level', {'intermediate', 'advanced'})NotInCondition<T>
True when a property value is not in a set of values.
NotInCondition<String>('status', {'deleted', 'archived'})
// Builder shorthand
PropertyCollectionBuilder.whenNotIn<String>('status', {'deleted', 'archived'})HasValueCondition
True when a property exists and has a non-null value.
HasValueCondition('instructor')
// Builder shorthand
PropertyCollectionBuilder.whenHasValue('instructor')ComparisonCondition<T extends num>
True when a numeric property passes a comparison. Supports four operators.
ComparisonCondition<int>(
propertyKey: 'capacity',
compareValue: 10,
operator: ComparisonOperator.greaterThan,
)
// Builder shorthands
PropertyCollectionBuilder.whenGreaterThan<int>('capacity', 10)
PropertyCollectionBuilder.whenLessThan<int>('capacity', 100)Available operators:
| Operator | Description |
|---|---|
ComparisonOperator.greaterThan | value > compareValue |
ComparisonOperator.greaterThanOrEqual | value >= compareValue |
ComparisonOperator.lessThan | value < compareValue |
ComparisonOperator.lessThanOrEqual | value <= compareValue |
AndCondition
True when all child conditions are true.
AndCondition([
EqualsCondition<bool>('advanced', true),
ComparisonCondition<int>(
propertyKey: 'capacity',
compareValue: 0,
operator: ComparisonOperator.greaterThan,
),
])
// Builder shorthand
PropertyCollectionBuilder.whenAll([
PropertyCollectionBuilder.whenTrue('advanced'),
PropertyCollectionBuilder.whenGreaterThan<int>('capacity', 0),
])Dependencies are the union of all child dependencies.
OrCondition
True when any child condition is true.
OrCondition([
EqualsCondition<String>('mode', 'auto'),
EqualsCondition<bool>('override', true),
])
// Builder shorthand
PropertyCollectionBuilder.whenAny([
PropertyCollectionBuilder.when<String>('mode', 'auto'),
PropertyCollectionBuilder.whenTrue('override'),
])NotCondition
Inverts another condition.
NotCondition(EqualsCondition<bool>('locked', true))There is no builder shorthand for NotCondition. Use the constructor directly.
AlwaysTrueCondition
Always returns true. Useful as a default or placeholder.
const AlwaysTrueCondition()AlwaysFalseCondition
Always returns false. Useful for permanently hiding a property.
const AlwaysFalseCondition()CustomCondition
Uses a function for evaluation. Provides maximum flexibility when built-in conditions are insufficient.
CustomCondition(
dependencies: ['level', 'capacity'],
evaluator: (collection) {
final level = collection.getValue<String>('level');
final capacity = collection.getValue<int>('capacity');
return level == 'advanced' && capacity > 20;
},
)
// Builder shorthand
PropertyCollectionBuilder.whenCustom(
dependencies: ['level', 'capacity'],
evaluator: (collection) {
final level = collection.getValue<String>('level');
final capacity = collection.getValue<int>('capacity');
return level == 'advanced' && capacity > 20;
},
)LMS Example: Conditional Course Settings
enum EnrollmentType { open, limited, invitation }
final b = PropertyCollectionBuilder();
b.group('enrollment', 'Enrollment');
b.enumeration<EnrollmentType>('enrollmentType', 'Enrollment Type',
options: [
EnumOption(EnrollmentType.open, 'Open'),
EnumOption(EnrollmentType.limited, 'Limited'),
EnumOption(EnrollmentType.invitation, 'Invitation Only'),
],
defaultValue: EnrollmentType.open,
);
// Only show capacity when enrollment is limited
b.integer('capacity', 'Max Capacity',
defaultValue: 30,
visibleCondition: PropertyCollectionBuilder.when<EnrollmentType>(
'enrollmentType', EnrollmentType.limited,
),
);
// Show waitlist option when limited AND capacity > 0
b.boolean('enableWaitlist', 'Enable Waitlist',
defaultValue: false,
visibleCondition: PropertyCollectionBuilder.whenAll([
PropertyCollectionBuilder.when<EnrollmentType>(
'enrollmentType', EnrollmentType.limited,
),
PropertyCollectionBuilder.whenGreaterThan<int>('capacity', 0),
]),
);
// Show invitation code when invitation type
b.string('invitationCode', 'Invitation Code',
visibleCondition: PropertyCollectionBuilder.when<EnrollmentType>(
'enrollmentType', EnrollmentType.invitation,
),
);Condition Summary Table
| Condition | Dependencies | Builder Shorthand |
|---|---|---|
EqualsCondition<T> | [propertyKey] | when<T>(key, value) |
NotEqualsCondition<T> | [propertyKey] | whenNot<T>(key, value) |
InCondition<T> | [propertyKey] | whenIn<T>(key, values) |
NotInCondition<T> | [propertyKey] | whenNotIn<T>(key, values) |
HasValueCondition | [propertyKey] | whenHasValue(key) |
ComparisonCondition<T> | [propertyKey] | whenGreaterThan<T>() / whenLessThan<T>() |
AndCondition | Union of children | whenAll(conditions) |
OrCondition | Union of children | whenAny(conditions) |
NotCondition | Same as child | (direct constructor) |
AlwaysTrueCondition | [] | (direct constructor) |
AlwaysFalseCondition | [] | (direct constructor) |
CustomCondition | Explicit list | whenCustom(deps, fn) |
Next Steps
- Validation -- PropertyValidator and built-in validators
- Dynamic Behavior Guide -- Conditions, derivations, and reactive updates
- Dependent Properties Pattern -- Chained visibility patterns