Filtering Fields available #806
-
Hi I've tried looking to see if this question has been asked previously but I can't seem to find any indication of it. I have a use case where I would like to split apart the fields that are selectable. By this I mean I have 4 fields, however not all these fields can be used together. In the below (contrived) example the top two fields can be used together and the bottom two fields can be used together.
The end result would be if the isMusician Field has been selected when trying to add a new rule only the instrument Field would appear and the bottom two fields would be filtered out. The same logic would then apply for when any of the other fields are selected. Ideally this filtering would apply against all Fields in the entire query i.e. so no child/parent Groups/Rules can invalidate the above constraint. I initially thought this was catered for via the OptionListGroup but I have since realised that is primarily for grouping Fields together and adding a label and not for filtering potential field options. My second attempt was at creating a custom FieldSelector, but I've been struggling to get this to work. I am currently using the AntD styling library and I am somewhat unsure of how to use the AntD specific FieldSelector. I see it is within the antdControlElements exported value but I can't necessarily access it and use it as a component when I create my CustomWrapper. For example this is what I currently have:
If I could get any assistance on how I would tackle the problem of filtering Fields that are selectable or with how to create a custom FieldSelector that can leverage the underlying AntdFieldSelector I'd appreciate it :) Ps. I'm currently using ReactQueryBuilder v6.5.5 |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment 1 reply
-
Here's a small example using RQB v7. You can do the same thing in v6, but it's more convoluted. https://codesandbox.io/p/devbox/hzwyhd?file=%2Fsrc%2FApp.tsx This example guarantees a rule in the first position by conditionally hiding the "remove rule" button. It implements a custom field selector that displays only the "Is a..." options for the first rule, and only those that are in the same To enforce the "group" constraint on all rules, I made it where the query would just get wiped out if the user changes the value of the first rule. Probably not what you want, but I'd need to know more about the business logic to properly cover that case. You might want to use query validation. import { AntDActionElement, AntDValueSelector, QueryBuilderAntD,} from '@react-querybuilder/antd';
import { useState } from 'react';
import type { ActionProps, Field, FullField, Path, RuleGroupType, RuleType } from 'react-querybuilder';
import { QueryBuilder, ValueSelectorProps, defaultOperators, formatQuery, getOption, pathsAreEqual, useQueryBuilderQuery } from 'react-querybuilder';
import './styles.scss';
const operators = defaultOperators.filter(op => op.name === '=');
const fields: Field[] = [
{
name: 'isMusician',
label: 'Is a musician',
valueEditorType: 'checkbox',
operators,
defaultValue: false,
group: 'music',
},
{
name: 'instrument',
label: 'Primary instrument',
valueEditorType: 'select',
values: [
{ name: 'guitar', label: 'Guitar' },
{ name: 'piano', label: 'Piano' },
{ name: 'drums', label: 'Drums' },
{ name: 'cowbell', label: 'Cowbell' },
],
defaultValue: 'Cowbell',
operators,
group: 'music',
},
{
name: 'isArtist',
label: 'Is an Artist',
valueEditorType: 'checkbox',
operators,
defaultValue: false,
group: 'art',
},
{
name: 'artMedium',
label: 'Primary Art Medium',
valueEditorType: 'select',
values: [
{ name: 'painting', label: 'Painting' },
{ name: 'sculpture', label: 'Sculpture' },
{ name: 'photography', label: 'Photography' },
],
operators,
group: 'art',
},
];
const initialQuery: RuleGroupType = {
combinator: 'and',
rules: [{ field: 'isMusician', operator: '=', value: true }],
};
export const MyFieldSelector = (props: ValueSelectorProps) => {
const query = useQueryBuilderQuery();
// For the first rule, only show "is a..." fields
if (pathsAreEqual(props.path, [0])) {
const options = (props.schema.fields as FullField[]).filter(f =>
f.name.match(/^is[A-Z]/)
);
// This will wipe out the query if the user changes the value of the first rule.
// Probably not exactly what you want, but just an example.
const handleOnChange = (value: string) => {
if (value !== props.value) {
props.schema.dispatchQuery({
combinator: 'and',
rules: [{ field: value, operator: '=', value: true }],
});
} else {
props.handleOnChange(value);
}
};
return (
<AntDValueSelector
{...props}
options={options}
handleOnChange={handleOnChange}
/>
);
}
// For other rules, show only the fields with the same "group" as the first rule
const { field } = query.rules[0] as RuleType;
const { group } = getOption(props.schema.fields, field)!;
const options = (props.schema.fields as FullField[]).filter(
f => f.group === group
);
return <AntDValueSelector {...props} options={options} />;
};
const RuleRemover = (props: ActionProps) =>
pathsAreEqual(props.path, [0]) ? null : <AntDActionElement {...props} />;
const onAddRule = (r: RuleType, _pp: Path, query: RuleGroupType) => {
const field = (query.rules[0] as RuleType).field;
return { ...r, field };
};
export const App = () => {
const [query, setQuery] = useState(initialQuery);
return (
<div>
<QueryBuilderAntD>
<QueryBuilder
fields={fields}
query={query}
onQueryChange={setQuery}
onAddRule={onAddRule}
controlElements={{
fieldSelector: MyFieldSelector,
removeRuleAction: RuleRemover,
}}
/>
</QueryBuilderAntD>
<h4>Query</h4>
<pre>
<code>{formatQuery(query, 'json')}</code>
</pre>
</div>
);
}; |
Beta Was this translation helpful? Give feedback.
Here's a small example using RQB v7. You can do the same thing in v6, but it's more convoluted.
https://codesandbox.io/p/devbox/hzwyhd?file=%2Fsrc%2FApp.tsx
This example guarantees a rule in the first position by conditionally hiding the "remove rule" button. It implements a custom field selector that displays only the "Is a..." options for the first rule, and only those that are in the same
group
(a custom field property) for all other rules.To enforce the "group" constraint on all rules, I made it where the query would just get wiped out if the user changes the value of the first rule. Probably not what you want, but I'd need to know more about the business logic to properly cover thatβ¦