Skip to content

Dependent Properties

This pattern covers how to create chains of dependent properties where one property's visibility or enabled state depends on the values of other properties.

Simple Dependency

The most common pattern: show property B when property A has a specific value.

dart
b.boolean('advanced', 'Show Advanced Options', defaultValue: false);

b.integer('threadCount', 'Thread Count',
  defaultValue: 4,
  visibleCondition: PropertyCollectionBuilder.whenTrue('advanced'),
);

b.integer('bufferSize', 'Buffer Size (KB)',
  defaultValue: 256,
  visibleCondition: PropertyCollectionBuilder.whenTrue('advanced'),
);

Chained Dependencies

Properties that depend on the visibility of other dependent properties. Because conditions evaluate against values (not visibility), chained conditions must reference the same root dependency.

dart
enum DataSource { none, api, database, file }

b.enumeration<DataSource>('dataSource', 'Data Source',
  options: [
    EnumOption(DataSource.none, 'None'),
    EnumOption(DataSource.api, 'REST API'),
    EnumOption(DataSource.database, 'Database'),
    EnumOption(DataSource.file, 'File Upload'),
  ],
  defaultValue: DataSource.none,
);

// Level 1: visible when data source is API
b.string('apiEndpoint', 'API Endpoint',
  visibleCondition: PropertyCollectionBuilder.when<DataSource>(
    'dataSource', DataSource.api,
  ),
);

// Level 1: visible when data source is API
b.boolean('useAuth', 'Require Authentication',
  defaultValue: false,
  visibleCondition: PropertyCollectionBuilder.when<DataSource>(
    'dataSource', DataSource.api,
  ),
);

// Level 2: visible when data source is API AND auth is enabled
b.string('apiKey', 'API Key',
  required: true,
  visibleCondition: PropertyCollectionBuilder.whenAll([
    PropertyCollectionBuilder.when<DataSource>('dataSource', DataSource.api),
    PropertyCollectionBuilder.whenTrue('useAuth'),
  ]),
);

// Level 1: visible when data source is database
b.string('connectionString', 'Connection String',
  visibleCondition: PropertyCollectionBuilder.when<DataSource>(
    'dataSource', DataSource.database,
  ),
);

// Level 1: visible when data source is file
b.string('filePath', 'File Path',
  visibleCondition: PropertyCollectionBuilder.when<DataSource>(
    'dataSource', DataSource.file,
  ),
);

Compound Conditions

Combine multiple independent properties to control visibility:

dart
b.boolean('enableNotifications', 'Enable Notifications', defaultValue: false);
b.boolean('enableEmail', 'Enable Email', defaultValue: false);

// Only show email settings when BOTH notifications AND email are enabled
b.string('emailAddress', 'Notification Email',
  visibleCondition: PropertyCollectionBuilder.whenAll([
    PropertyCollectionBuilder.whenTrue('enableNotifications'),
    PropertyCollectionBuilder.whenTrue('enableEmail'),
  ]),
);

// Show SMS settings when notifications are on AND email is OFF
b.string('phoneNumber', 'SMS Number',
  visibleCondition: PropertyCollectionBuilder.whenAll([
    PropertyCollectionBuilder.whenTrue('enableNotifications'),
    PropertyCollectionBuilder.whenFalse('enableEmail'),
  ]),
);

Numeric Thresholds

Show properties based on numeric values crossing thresholds:

dart
b.integer('teamSize', 'Team Size', defaultValue: 1);

// Show team lead field when team has 2+ members
b.string('teamLead', 'Team Lead',
  visibleCondition: PropertyCollectionBuilder.whenGreaterThan<int>(
    'teamSize', 1,
  ),
);

// Show department selection when team has 10+ members
b.enumeration<String>('department', 'Department',
  options: [...],
  defaultValue: 'general',
  visibleCondition: PropertyCollectionBuilder.whenGreaterThan<int>(
    'teamSize', 9,
  ),
);

Enabled vs. Visible

Use enabledCondition to show a property but prevent editing:

dart
b.enumeration<String>('status', 'Status',
  options: [
    EnumOption('draft', 'Draft'),
    EnumOption('published', 'Published'),
    EnumOption('archived', 'Archived'),
  ],
  defaultValue: 'draft',
);

// Title is always visible, but locked when published
b.string('title', 'Title',
  required: true,
  enabledCondition: PropertyCollectionBuilder.when<String>('status', 'draft'),
);

// Delete option only visible when archived
b.boolean('confirmDelete', 'Confirm Deletion',
  visibleCondition: PropertyCollectionBuilder.when<String>(
    'status', 'archived',
  ),
);

Using OrCondition for Alternatives

Show a property when any of several conditions is true:

dart
b.enumeration<String>('role', 'Role',
  options: [
    EnumOption('viewer', 'Viewer'),
    EnumOption('editor', 'Editor'),
    EnumOption('admin', 'Admin'),
    EnumOption('owner', 'Owner'),
  ],
  defaultValue: 'viewer',
);

// Show permission settings for editor, admin, or owner
b.boolean('canPublish', 'Can Publish',
  visibleCondition: PropertyCollectionBuilder.whenIn<String>(
    'role', {'editor', 'admin', 'owner'},
  ),
);

// Show danger zone only for admin or owner
b.boolean('canDelete', 'Can Delete',
  visibleCondition: PropertyCollectionBuilder.whenIn<String>(
    'role', {'admin', 'owner'},
  ),
);

Next Steps