Skip to main content
Version: Next

Path concepts

While the id property can uniquely identify a rule or group, an id won't naturally indicate anything about the position of the object within the query hierarchy. For that reason, React Query Builder uses the concept of a "path" to locate and update query objects.

The path property is an array of integers unique to each rule and group within a query. The query object itself (the root group) has a path of []. All other rules and groups within the query have a path that corresponds to their position within the rules array(s) of their ancestor group(s).

The path of any object (rule or group) is equivalent to the path of its parent group, with the index of the object within its parent's rules array pushed onto the end. You can think of it like this: path = [...parentPath, index].

Consider the following query. The respective path for each rule and group is commented above it, along with a short explanation.

// [] (the root group)
const query: RuleGroupType = {
combinator: 'and',
rules: [
// [0] (the first, aka zeroth, element in the root rules array)
{ field: 'f1', operator: '=', value: 'v1' },
// [1] (the second element in the root rules array is a sub-group)
{
combinator: 'or',
rules: [
// [1, 0] (the first element within the rules array
// of the group occupying the second position
// in the root rules array)
{ field: 'f2', operator: '=', value: 'v2' },
// [1, 1] (the second element within the rules array
// of the group occupying the second position
// in the root rules array)
{ field: 'f3', operator: '=', value: 'v3' },
],
},
],
};

The path of the top-most rule in the query is [0], 0 being the index of that rule within the root group's rules array. The path of the first sub-group in the query is [1], again according to its index within the outermost rules array. Each child rule of that group has a path that begins with 1 (the path of its parent), followed by its own index.

Finding a path

Use the findPath function to locate a specific rule or group for examination or update. Given the query above:

findPath([1, 0], query);

would return this object:

{ "field": "f2", "operator": "=", "value": "v2" }

Example

In most scenarios you won't need to interact with the path attribute, but it can come in handy in certain situations. One such situation is if you need to access other parts of the query from within a custom component.

Say you have a custom value editor that needs to know the value of each of its sibling rules. You can get the full query object using the useQueryBuilderQuery hook (which connects to React Query Builder's custom Redux implementation). You can then retrieve the sibling rules with a combination of getParentPath and findPath.

info

Prior to version 7, custom components only received props relevant to the rule or group they acted on. You could augment these default props with other data or information--the root query object, for example--by using the context prop.

The context prop is still available, but is not necessary for retrieving the query.

import {
  RuleGroupType,
  RuleType,
  ValueEditor,
  ValueEditorProps,
  findPath,
  getParentPath,
  useQueryBuilderQuery,
} from 'react-querybuilder';

export const CustomValueEditor = (props: ValueEditorProps) => {
  // Get the full query object
  const query = useQueryBuilderQuery();
  // Get the path of this rule's parent group
  const parentPath = getParentPath(props.path);
  // Find the parent group object in the query
  const parentGroup = findPath(parentPath, query) as RuleGroupType;
  const id = findPath(props.path, query)!.id;
  // Get a comma-separated list of all sibling rule values
  const siblingValues = (
    parentGroup.rules.filter(
      r =>
        // filter out groups
        !('rules' in r) &&
        // filter out self
        r.id !== id
    ) as RuleType[]
  )
    // map the `value` property
    .map(r => r.value)
    // join with comma
    .join(', ');

  return (
    <div style={{ display: 'flex', flexDirection: 'column' }}>
      <ValueEditor {...props} />
      <span>Others: {siblingValues}</span>
    </div>
  );
};