2

I'm trying to create a query that takes the initial fields (kind, property, and property value). This part is straight forward. However for every additional query option/rule I want to disable the "kind" option and only leave the "property" and "property value" because the database only accepts one "kind" but multiple "properties" and "property values". Here is the library: https://github.com/react-querybuilder/react-querybuilder#usage

Here is a visual

React-Query-Builder

1 Answer 1

2

I think I've got something working like you want in this codesandbox. I had to use a lot of custom components, but they all fall back to the default components with relatively little logic on their own -- hiding themselves based on the level prop or just always hiding.

Relevant code is below:

import { useState } from "react";
import QueryBuilder, {
  ActionElement,
  ActionProps,
  ActionWithRulesProps,
  FieldSelectorProps,
  formatQuery,
  OperatorSelectorProps,
  RuleGroupType,
  RuleType,
  ValueEditor,
  ValueEditorProps,
  ValueSelector
} from "react-querybuilder";
import "react-querybuilder/dist/query-builder.css";

const fields = [
  { name: "first_name", label: "First Name" },
  { name: "email", label: "Email" },
  { name: "last_name", label: "Last Name" }
];

const defaultQuery: RuleGroupType = {
  id: "root",
  combinator: "and",
  rules: [
    {
      field: "last_name",
      operator: "=",
      value: ""
    },
    {
      id: "ruleGroup",
      combinator: "and",
      rules: []
    }
  ]
};

const addRuleAction = (props: ActionWithRulesProps) => {
  if (props.level === 0) {
    return null;
  }
  return <ActionElement {...props} />;
};

const addGroupAction = () => null;

const removeGroupAction = () => null;

const removeRuleAction = (props: ActionProps) => {
  if (props.level === 0) {
    return null;
  }
  return <ActionElement {...props} />;
};

const combinatorSelector = () => null;

const fieldSelector = (props: FieldSelectorProps) => {
  if (props.level > 0) {
    return null;
  }
  return <ValueSelector {...props} />;
};

const operatorSelector = (props: OperatorSelectorProps) => {
  if (props.level === 0) {
    return null;
  }
  return <ValueSelector {...props} />;
};

const valueEditor = (props: ValueEditorProps) => {
  if (props.level === 0) {
    return null;
  }
  return <ValueEditor {...props} />;
};

export default function App() {
  const [query, setQuery] = useState<RuleGroupType>(defaultQuery);

  const onQueryChange = (q: RuleGroupType) => {
    const f = (q.rules[0] as RuleType).field;
    const newQuery = {
      ...q,
      rules: [
        q.rules[0],
        {
          ...q.rules[1],
          rules: (q.rules[1] as RuleGroupType).rules.map((r) => ({
            ...r,
            field: f
          }))
        }
      ]
    };

    setQuery(newQuery);
  };

  return (
    <>
      <QueryBuilder
        fields={fields}
        onQueryChange={onQueryChange}
        query={query}
        controlElements={{
          addRuleAction,
          addGroupAction,
          removeGroupAction,
          combinatorSelector,
          operatorSelector,
          removeRuleAction,
          fieldSelector,
          valueEditor
        }}
        getDefaultField={() => "last_name"}
      />
      <h3>Output:</h3>
      <pre>{formatQuery(query)}</pre>
    </>
  );
}
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.