Cascading / Dependent Dropdowns
Make one relation() dropdown's options filter automatically based on another field's currently selected value.
The idea
relation()'s $dependField/$dependOn parameters turn two ordinary relation fields into a parent/child pair: picking a value in the parent field re-fetches the child field's own options, filtered to only what belongs under the newly picked parent - a City field that only shows cities in the currently-selected Country, for example.
$dependOn names the OTHER relation field on this table to watch (it must itself be relation()-configured - there has to be a real dropdown to attach the cascade to). $dependField names the column on the child's own target table to filter by, compared against $dependOn's current value.
A 2-field example
A Country relation and a City relation, wired together - picking a country re-fetches the city dropdown's options (only cities whose country_id matches the country just picked):
$xcrud->relation('country', 'meta_location', 'id', 'local_name', "type = 'CO'");
$xcrud->relation(
'city', 'meta_location', 'id', 'local_name',
"type = 'CI'", null, false, ' ', null, 'in_location', 'country'
);
Here 'in_location' is $dependField (the column on meta_location to filter by) and 'country' is $dependOn (the name of the parent relation field on this table). Old xCrud's convention of passing '' rather than omitting a trailing argument is accepted for $where/$orderBy/$tree too - '' is treated the same as leaving it out.
Parameters that matter here
| Parameter | Type | Default | Description |
|---|---|---|---|
$dependField | string|null | null | Column on this field's own target table to filter by (e.g. in_location). |
$dependOn | string|null | null | Name of the parent relation() field on this table whose current value drives the filter. |
The two must either both be set or both be left out - one without the other has nothing to pair a filter column with, and relation() throws rather than silently ignoring the mismatch.
Multi-level chains
Chains longer than two fields work the same way, one link at a time - each link only knows about its own immediate parent. A Country → Region → City chain against a single self-referencing table:
$xcrud->relation('country', 'meta_location', 'id', 'local_name', "type = 'CO'");
$xcrud->relation(
'region', 'meta_location', 'id', 'local_name',
"type = 'RE'", null, false, ' ', null, 'in_location', 'country'
);
$xcrud->relation(
'city', 'meta_location', 'id', 'local_name',
"type = 'CI'", null, false, ' ', null, 'in_location', 'region'
);
Picking a country re-fetches region's options (type = 'RE' AND in_location = {country's id}) and resets both region and city, since city's own parent (region) just became stale too. Picking a region similarly re-fetches city's options and resets city. A single-level cascade (e.g. Office → Manager, filtering employees down to one office's own staff) works exactly the same way with just one link.
A second example: Office → Manager
$xcrud->relation('office', 'offices', 'officeCode', 'city');
$xcrud->relation(
'manager', 'employees', 'employeeNumber', ['firstName', 'lastName'],
null, null, false, ' ', null, 'officeCode', 'office'
);
Here the manager dropdown's target table is employees, filtered by its own officeCode column against whatever office is currently picked - and the label is built from two columns (firstName, lastName) joined by the default ' ' separator.