Is your feature request related to a problem? Please describe.
The Query component in @react-awesome-query-builder has an onChange parameter; this is used for callbacks when there is any change to the tree.
<Query
{...config}
value={searchTreeBuilderState.tree}
onChange={onChange}
renderBuilder={renderBuilder}
/>
So What I'd like is some way of either "cancelling" onChange calls, or have some sort of preOnChange callback which can check results. In our case, we want to do that because we want a confirmatory dialog to show to the user when they press the "Delete" button on either a rule or a group, but only when certain conditions exist. We don't want a confirmatory dialog to be shown every time the user presses the "Delete" button.
We are using React Awesome Query Builder to construct parameterised queries - queries that have placeholders for gaps in the query that users can fill later. Full queries are things of the sort "Find all contacts who are older than 55"; parameterised queries are "Find all contacts who are older than placeholder". We already use React Awesome Query Builder for the first situation; we are having some success for the second. However, we only want to show confirmatory dialogs when the users delete rules and groups with placeholders. So here's an attempt at trying to put a confirmatory dialog into our onChange callback:
const searchTreeBuilderStateTreeRef = useRef<ImmutableTree | undefined>(null);
const currentConfigRef = useRef<Config>(null);
const currentSearchTreeRef = useRef<SearchTreeNode | undefined>(null);
const onChange = useCallback(
(immutableTree: ImmutableTree, newConfig: Config, actionMeta?: ActionMeta) => {
// Tip: for better performance you can apply `throttle` - see `examples/demo`
const newPossibleSearchTree = mapToSearchTree(immutableTree, config);
if (
isTemplateMode &&
(['REMOVE_RULE', 'REMOVE_GROUP'] as (string | undefined)[]).includes(actionMeta?.type) &&
countAllPlaceholders(currentSearchTree) > countAllPlaceholders(newPossibleSearchTree)
) {
setChosenRuleOrGroup(actionMeta?.type || '');
currentSearchTreeRef.current = currentSearchTree;
currentConfigRef.current = newConfig;
searchTreeBuilderStateTreeRef.current = searchTreeBuilderState.tree;
setIsDialogOpen(true);
}
setIsFilterIncomplete(checkIsSearchTreeIncomplete(immutableTree));
setSearchTreeBuilderState((prevState) => ({
...prevState,
tree: immutableTree,
config: newConfig,
}));
onSearchTreeChange(newPossibleSearchTree);
},
// eslint-disable-next-line react-hooks/exhaustive-deps
[setIsFilterIncomplete, setSearchTreeBuilderState, onSearchTreeChange, config]
);
The (['REMOVE_RULE', 'REMOVE_GROUP'] as (string | undefined)[]).includes(actionMeta?.type) part is checking whether the onChange is being pressed if the user has pressed the "Delete" button on a Rule or a Group", and the countAllPlaceholders(currentSearchTree) > countAllPlaceholders(newPossibleSearchTree) is telling us if the number of placeholders in the new query is less than in the old query.
If I would be writing the code as I'd expect, I'd write setIsDialogOpen(true) immediately to set a boolean variable to display a confirmatory dialog with "Cancel" and "Remove" buttons. But what I have to do instead is write data to useRef variables, and then setIsDialogOpen(true) to show the dialog with "Cancel" and "Remove" buttons.
If the user presses the "Remove", this code is called
const handleRemove = async () => setIsDialogOpen(false);
Then the dialog vanishes. If the person presses the "Cancel" button, the this is called:
const handleRevert = async () => {
setIsFilterIncomplete(checkIsSearchTreeIncomplete(searchTreeBuilderStateTreeRef.current!));
setSearchTreeBuilderState((prevState) => ({
...prevState,
tree: searchTreeBuilderStateTreeRef.current!,
config: currentConfigRef.current!,
}));
onSearchTreeChange(currentSearchTreeRef.current!);
setIsDialogOpen(false);
};
Then the useRef values are used to reset the state to what it was before the delete button was pressed.
So what's the problem here? Well, the actual components in the React Awesome Query Builder disappear behind the dialog disappear as soon as the Delete button is pressed on React Awesome Query Builder, rather than when the user presses the Remove button on the dialog.
If the person presses the Cancel button, then the components in React Awesome Query Builder reappear. That is not normal UI.
Describe the solution I'd like
Some sort of flexible way to allow me to write code to check the contents in the React Awesome Query Builder for certain properties before onChange is called with 'REMOVE_RULE' or 'REMOVE_GROUP'. Like perhaps a BEFORE_'REMOVE_RULE' or BEFORE_'REMOVE_GROUP' values for actionMeta?.type. Then perhaps I can set some "cancel" state and not have to save stuff to useRef variables.
Describe alternatives you've considered
I have looked at existing issues in this git repository's backlog. Add listener to delete button - #95 is "all or nothing", and there seems to be little capacity to custom the body text of the dialog. Render custom delete button #436 could one possible way around it, but I want to write confirmatory dialogs, not overwrite the look and feel of delete buttons
Additional context
I'll try to save screenshots tomorrow if it doesn't make sense.
Is your feature request related to a problem? Please describe.
The
Querycomponent in@react-awesome-query-builderhas anonChangeparameter; this is used for callbacks when there is any change to the tree.So What I'd like is some way of either "cancelling"
onChangecalls, or have some sort ofpreOnChangecallback which can check results. In our case, we want to do that because we want a confirmatory dialog to show to the user when they press the "Delete" button on either a rule or a group, but only when certain conditions exist. We don't want a confirmatory dialog to be shown every time the user presses the "Delete" button.We are using React Awesome Query Builder to construct parameterised queries - queries that have placeholders for gaps in the query that users can fill later. Full queries are things of the sort "Find all contacts who are older than 55"; parameterised queries are "Find all contacts who are older than placeholder". We already use React Awesome Query Builder for the first situation; we are having some success for the second. However, we only want to show confirmatory dialogs when the users delete rules and groups with placeholders. So here's an attempt at trying to put a confirmatory dialog into our
onChangecallback:The
(['REMOVE_RULE', 'REMOVE_GROUP'] as (string | undefined)[]).includes(actionMeta?.type)part is checking whether theonChangeis being pressed if the user has pressed the "Delete" button on a Rule or a Group", and thecountAllPlaceholders(currentSearchTree) > countAllPlaceholders(newPossibleSearchTree)is telling us if the number of placeholders in the new query is less than in the old query.If I would be writing the code as I'd expect, I'd write
setIsDialogOpen(true)immediately to set a boolean variable to display a confirmatory dialog with "Cancel" and "Remove" buttons. But what I have to do instead is write data touseRefvariables, and thensetIsDialogOpen(true)to show the dialog with "Cancel" and "Remove" buttons.If the user presses the "Remove", this code is called
Then the dialog vanishes. If the person presses the "Cancel" button, the this is called:
Then the
useRefvalues are used to reset the state to what it was before the delete button was pressed.So what's the problem here? Well, the actual components in the React Awesome Query Builder disappear behind the dialog disappear as soon as the Delete button is pressed on React Awesome Query Builder, rather than when the user presses the Remove button on the dialog.
If the person presses the Cancel button, then the components in React Awesome Query Builder reappear. That is not normal UI.
Describe the solution I'd like
Some sort of flexible way to allow me to write code to check the contents in the React Awesome Query Builder for certain properties before
onChangeis called with'REMOVE_RULE'or'REMOVE_GROUP'. Like perhaps aBEFORE_'REMOVE_RULE'orBEFORE_'REMOVE_GROUP'values foractionMeta?.type. Then perhaps I can set some "cancel" state and not have to save stuff touseRefvariables.Describe alternatives you've considered
I have looked at existing issues in this git repository's backlog. Add listener to delete button - #95 is "all or nothing", and there seems to be little capacity to custom the body text of the dialog. Render custom delete button #436 could one possible way around it, but I want to write confirmatory dialogs, not overwrite the look and feel of delete buttons
Additional context
I'll try to save screenshots tomorrow if it doesn't make sense.