Templates in React Query builder component

30 Jan 202324 minutes to read

Templates allows users to define customized header and own user interface for columns.

Header Template

Header Template allows to define your own user interface for Header, which includes creating or deleting rules and groups and to customize the AND/OR condition and NOT condition options. To implement header template, you can create the user interface as React component and assign the values when requestType is header-template-create in actionBegin event.

In the following sample dropdown, splitbutton and button are used as the custom components in the header.

import { QueryBuilderComponent, ColumnsDirective, ColumnDirective } from '@syncfusion/ej2-react-querybuilder';
import * as React from 'react';
import * as ReactDom from 'react-dom';
import { HeaderTemplate } from './template';
function App() {
    let qryBldrObj;
    let importRules = {
        'condition': 'and', 'not': true,
        'rules': [{
                'field': 'Age',
                'label': 'Age',
                'operator': 'equal',
                'type': 'number',
                'value': 30
            },
            {
                'label': 'LastName',
                'field': 'LastName',
                'type': 'string',
                'operator': 'equal',
                'value': 'vinit'
            },
            {
                'condition': 'or',
                'rules': [{
                        'label': 'Age',
                        'field': 'Age',
                        'type': 'number',
                        'operator': 'equal',
                        'value': 34
                    }]
            }
        ]
    };
    function headerTemplate(props) {
        return (<HeaderTemplate {...props}/>);
    }
    return (<div>
        <QueryBuilderComponent width='100%' rule={importRules} headerTemplate={headerTemplate} id='querybuilder' enableNotCondition="true">
            <ColumnsDirective>
                <ColumnDirective field="EmployeeID" label="Employee ID" type="number"/>
                <ColumnDirective field="LastName" label="Last Name" type="string"/>
                <ColumnDirective field="FirstName" label="First Name" type="string"/>
                <ColumnDirective field="Age" label="Age" type="number"/>
                <ColumnDirective field="City" label="City" type="string"/>
                <ColumnDirective field="Country" label="Country" type="string"/>
            </ColumnsDirective>
        </QueryBuilderComponent>
    </div>);
}
export default App;
ReactDom.render(<App />, document.getElementById('querybuilder-component'));
import { QueryBuilderComponent, ColumnsDirective, ColumnDirective  } from '@syncfusion/ej2-react-querybuilder';
import { RuleModel } from '@syncfusion/ej2-querybuider';
import * as React from 'react';
import * as ReactDom from 'react-dom';
import { HeaderTemplate } from './template';
function App() {
    let qryBldrObj: QueryBuilderComponent;
    let importRules: RuleModel = {
            'condition': 'and', 'not': true,
            'rules': [{
                    'field': 'Age',
                    'label': 'Age',
                    'operator': 'equal',
                    'type': 'number',
                    'value': 30
                },
                {
                    'label': 'LastName',
                    'field': 'LastName',
                    'type': 'string',
                    'operator': 'equal',
                    'value': 'vinit'
                },
                {
                    'condition': 'or',
                    'rules': [{
                      'label': 'Age',
                      'field': 'Age',
                      'type': 'number',
                      'operator': 'equal',
                      'value': 34
                    }]
                }
            ]
        };
    function headerTemplate(props) {
        return (<HeaderTemplate {...props}/>);
    }

    return (<div>
        <QueryBuilderComponent width='100%' rule={importRules} headerTemplate= {headerTemplate} id='querybuilder' enableNotCondition ="true" >
            <ColumnsDirective>
                <ColumnDirective field="EmployeeID" label="Employee ID" type="number"/>
                <ColumnDirective field="LastName" label="Last Name" type="string"/>
                <ColumnDirective field="FirstName" label="First Name" type="string"/>
                <ColumnDirective field="Age" label="Age" type="number"/>
                <ColumnDirective field="City" label="City" type="string"/>
                <ColumnDirective field="Country" label="Country" type="string"/>
            </ColumnsDirective>
        </QueryBuilderComponent>
    </div>);
}
export default App;
ReactDom.render(<App />,document.getElementById('querybuilder-component'));
import * as React from 'react';
import { DropDownListComponent } from '@syncfusion/ej2-react-dropdowns';
import { getComponent, closest } from '@syncfusion/ej2-base';
import { CheckBoxComponent, ButtonComponent } from '@syncfusion/ej2-react-buttons';
import { DropDownButtonComponent } from '@syncfusion/ej2-react-splitbuttons';
export function HeaderTemplate(props) {
    let ds = [{ 'key': 'AND', 'value': 'and' }, { 'key': 'OR', 'value': 'or' }];
    let qryBldrObj;
    let fields = { text: 'key', value: 'value' };
    let ddbitems = [
        {
            text: 'AddGroup',
            iconCss: 'e-icons e-add-icon e-addgroup'
        },
        {
            text: 'AddCondition',
            iconCss: 'e-icons e-add-icon e-addrule'
        }
    ];
    let state = Object.assign({}, props);
    qryBldrObj = getComponent(document.getElementById('querybuilder'), 'query-builder');
    function onChange(args) {
        qryBldrObj.notifyChange(args.checked, args.event.target, 'not');
    }
    function conditionChange(args) {
        qryBldrObj.notifyChange(args.value, args.element, 'condition');
    }
    function onSelect(event) {
        let addbtn = closest(event.element, '.e-dropdown-popup');
        let ddbId = addbtn.id;
        let ddb = ddbId.split('_');
        if (event.item.text === 'AddGroup') {
            qryBldrObj.addGroups([{ condition: 'or', 'rules': [{}], not: false }], ddb[1]);
        }
        else if (event.item.text === 'AddCondition') {
            qryBldrObj.addRules([{}], ddb[1]);
        }
    }
    function onClick(args) {
        qryBldrObj.deleteGroup(closest(args.target.offsetParent, '.e-group-container'));
    }
    const args = state;
    return (<div className="e-groupheader">
        {(() => {
            if (args.notCondition !== undefined) {
                return (<button className="e-cb-wrapper">
                    <CheckBoxComponent id={args.ruleID + "_notOption"} label="not" checked={args.notCondition} change={onChange}/>
                </button>);
            }
        })()}
        <DropDownListComponent id={args.ruleID + "_cndtn"} cssClass='e-custom-group-btn' dataSource={ds} fields={fields} value={args.condition} change={conditionChange}/>
        <DropDownButtonComponent id={args.ruleID + "_addbtn"} items={ddbitems} cssClass="e-round e-small e-caret-hide e-addrulegroup e-add-btn" iconCss="e-icons e-add-icon" select={onSelect}></DropDownButtonComponent>
        {(() => {
            if (args.ruleID !== "querybuilder_group0") {
                return (<ButtonComponent id={args.ruleID + "_dltbtn"} cssClass='e-btn e-delete-btn e-lib e-small e-round e-icon-btn' iconCss="e-btn-icon e-icons e-delete-icon" onClick={onClick}></ButtonComponent>);
            }
        })()}
        </div>);
}
import * as React from 'react';
import { DropDownListComponent } from '@syncfusion/ej2-react-dropdowns';
import { getComponent,  closest } from '@syncfusion/ej2-base';
import { CheckBoxComponent, ButtonComponent} from '@syncfusion/ej2-react-buttons';
import { DropDownButtonComponent } from '@syncfusion/ej2-react-splitbuttons';
import { QueryBuilderComponent } from '@syncfusion/ej2-react-querybuider';
import { QueryBuilder, ActionEventArgs, RuleModel } from '@syncfusion/ej2-querybuider';
import { ItemModel, MenuEventArgs } from '@syncfusion/ej2-splitbuttons';


export function HeaderTemplate(props) {
 let ds: { [key: string]: Object }[] = [{'key': 'AND', 'value': 'and'},{'key': 'OR', 'value': 'or'}];
 let qryBldrObj: QueryBuilderComponent;
 let fields: object = { text: 'key', value: 'value'};
 let ddbitems: ItemModel[] = [
    {
        text: 'AddGroup',
        iconCss: 'e-icons e-add-icon e-addgroup'
    },
    {
        text: 'AddCondition',
        iconCss: 'e-icons e-add-icon e-addrule'
    }];

    let state = Object.assign({}, props);
    qryBldrObj = getComponent(document.getElementById('querybuilder'), 'query-builder') as QueryBuilder;

    function onChange(args: any): void{
        qryBldrObj.notifyChange(args.checked, args.event.target, 'not');
    }
    function conditionChange(args: any): void{
        qryBldrObj.notifyChange(args.value, args.element, 'condition');
    }
    function onSelect(event: MenuEventArgs): void{
        let addbtn: Element= closest(event.element,'.e-dropdown-popup'); 
        let ddbId: string = addbtn.id; let ddb: string[] = ddbId.split('_'); 
        if (event.item.text === 'AddGroup') {
            qryBldrObj.addGroups([{condition: 'or', 'rules': [{}], not: false}], ddb[1]);
        } else if (event.item.text === 'AddCondition') {
            qryBldrObj.addRules([{}], ddb[1]);
        }
    }
    function onClick(args: any): void{
        qryBldrObj.deleteGroup(closest(args.target.offsetParent, '.e-group-container'));
    }
    const args: ActionEventArgs = state;
    return (<div className = "e-groupheader">
        {(()=> {
            if(args.notCondition !== undefined){
                return( <button className = "e-cb-wrapper">
                    <CheckBoxComponent id = {args.ruleID + "_notOption"} label="not" checked={args.notCondition}  change={onChange}/>
                </button>);
            }
        })()}
        <DropDownListComponent id = {args.ruleID + "_cndtn"} cssClass = 'e-custom-group-btn' dataSource={ds}  fields={fields}  value={args.condition} change={conditionChange}/>
        <DropDownButtonComponent id = {args.ruleID + "_addbtn"} items={ddbitems} cssClass= "e-round e-small e-caret-hide e-addrulegroup e-add-btn" iconCss="e-icons e-add-icon" select={onSelect}></DropDownButtonComponent>
        {(()=> {
            if (args.ruleID !== "querybuilder_group0") {
                return(<ButtonComponent id = {args.ruleID + "_dltbtn"} cssClass = 'e-btn e-delete-btn e-lib e-small e-round e-icon-btn' iconCss="e-btn-icon e-icons e-delete-icon" onClick={onClick} ></ButtonComponent>)
            }
        })()}
        </div>
    );
}

Column Template

Template allows you to define your own input widgets for columns. To implement template, you can define the following functions

  • create: Creates the custom component.
  • write: Wire events for the custom component.
  • Destroy: Destroy the custom component.

In the following sample, dropdown is used as the custom component in the PaymentMode column.

import { getComponent } from '@syncfusion/ej2-base';
import { DropDownList, MultiSelect } from '@syncfusion/ej2-react-dropdowns';
import { QueryBuilderComponent } from '@syncfusion/ej2-react-querybuilder';
import * as React from 'react';
import * as ReactDom from 'react-dom';
// @ts-ignore
import { expenseData } from '../datasource.ts';
function App() {
    let qryBldrObj;
    let elem;
    let dropDownObj;
    let multiSelectObj;
    let inOperators = ['in', 'notin'];
    let filter = [
        {
            field: 'PaymentMode', label: 'Payment Mode', operators: [
                { key: 'Equal', value: 'equal' },
                { key: 'Not Equal', value: 'notequal' },
                { key: 'In', value: 'in' },
                { key: 'Not In', value: 'notin' }
            ], template: {
                create: () => {
                    elem = document.createElement('input');
                    elem.setAttribute('type', 'text');
                    return elem;
                },
                destroy: (args) => {
                    multiSelectObj = getComponent(document.getElementById(args.elementId), 'multiselect');
                    if (multiSelectObj) {
                        multiSelectObj.destroy();
                    }
                    dropDownObj = getComponent(document.getElementById(args.elementId), 'dropdownlist');
                    if (dropDownObj) {
                        dropDownObj.destroy();
                    }
                },
                write: (args) => {
                    const ds = ['Cash', 'Debit Card', 'Credit Card', 'Net Banking', 'Wallet'];
                    if (inOperators.indexOf(args.operator) > -1) {
                        multiSelectObj = new MultiSelect({
                            change: (e) => {
                                qryBldrObj.notifyChange(e.value, e.element);
                            },
                            dataSource: ds,
                            mode: 'CheckBox',
                            placeholder: 'Select Transaction',
                            value: args.values
                        });
                        multiSelectObj.appendTo('#' + args.elements.id);
                    }
                    else {
                        dropDownObj = new DropDownList({
                            change: (e) => {
                                qryBldrObj.notifyChange(e.itemData.value, e.element);
                            },
                            dataSource: ds,
                            value: args.values ? args.values : ds[0]
                        });
                        dropDownObj.appendTo('#' + args.elements.id);
                    }
                }
            }, type: 'string'
        },
        { field: 'Description', label: 'Description', type: 'string' },
        { field: 'Date', label: 'Date', type: 'date' }
    ];
    let importRules = {
        'condition': 'or',
        'rules': [{
                'field': 'PaymentMode',
                'label': 'PaymentMode',
                'operator': 'equal',
                'type': 'string',
                'value': 'Cash'
            }]
    };
    return (<QueryBuilderComponent dataSource={expenseData} columns={filter} width='100%' rule={importRules} ref={(scope) => { qryBldrObj = scope; }}/>);
}
export default App;
ReactDom.render(<App />, document.getElementById('querybuilder'));
import { getComponent } from '@syncfusion/ej2-base';
import { ChangeEventArgs, DropDownList, MultiSelect, MultiSelectChangeEventArgs } from '@syncfusion/ej2-react-dropdowns';
import { ColumnsModel, QueryBuilderComponent, RuleModel } from '@syncfusion/ej2-react-querybuilder';
import * as React from 'react';
import * as ReactDom from 'react-dom';
// @ts-ignore
import { expenseData } from '../datasource.ts';

function App() {
    let qryBldrObj: QueryBuilderComponent;
    let elem: HTMLElement;
    let dropDownObj: DropDownList;
    let multiSelectObj: MultiSelect;
    let inOperators: string [] = ['in', 'notin'];
    let filter: ColumnsModel[] = [
         {
            field: 'PaymentMode', label: 'Payment Mode', operators: [
                { key: 'Equal', value: 'equal' },
                { key: 'Not Equal', value: 'notequal' },
                { key: 'In', value: 'in' },
                { key: 'Not In', value: 'notin' }
            ], template: {
                create: () => {
                    elem = document.createElement('input');
                    elem.setAttribute('type', 'text');
                    return elem;
                },
                destroy: (args: { elementId: string }) => {
                    multiSelectObj = getComponent(document.getElementById(args.elementId) as HTMLElement, 'multiselect') as MultiSelect;
                    if (multiSelectObj) {
                        multiSelectObj.destroy();
                    }
                    dropDownObj = getComponent(document.getElementById(args.elementId) as HTMLElement, 'dropdownlist') as DropDownList;
                    if (dropDownObj) {
                        dropDownObj.destroy();
                    }
                },
                write: (args: { elements: Element, values: string[] | string, operator: string }) => {
                    const ds = ['Cash', 'Debit Card', 'Credit Card', 'Net Banking', 'Wallet'];
                    if (inOperators.indexOf(args.operator) > -1) {
                        multiSelectObj = new MultiSelect({
                            change: (e: MultiSelectChangeEventArgs) => {
                                qryBldrObj.notifyChange(e.value as string[], e.element);
                            },
                            dataSource: ds,
                            mode: 'CheckBox',
                            placeholder: 'Select Transaction',
                            value: args.values as string []
                        });
                        multiSelectObj.appendTo('#' + args.elements.id);
                    } else {
                        dropDownObj = new DropDownList({
                            change: (e: ChangeEventArgs) => {
                                qryBldrObj.notifyChange(e.itemData.value as string, e.element);
                            },
                            dataSource: ds,
                            value: args.values ? args.values as string : ds[0]
                        });
                        dropDownObj.appendTo('#' + args.elements.id);
                    }
                }
            }, type: 'string'
        },
        { field: 'Description', label: 'Description', type: 'string' },
        { field: 'Date', label: 'Date', type: 'date' }
    ];

    let importRules: RuleModel = {
            'condition': 'or',
            'rules': [{
                'field': 'PaymentMode',
                'label': 'PaymentMode',
                'operator': 'equal',
                'type': 'string',
                'value': 'Cash'
            }]
    };

    return (
        <QueryBuilderComponent dataSource={expenseData} columns={filter} width='100%' rule={importRules} ref={(scope) => { qryBldrObj = scope as QueryBuilderComponent; }} />
    );
}
export default App;
ReactDom.render(<App />,document.getElementById('querybuilder'));

Using Template

Template allows you to define your own input widgets for columns. To implement template, you can create the user interface as React component.

import { QueryBuilderComponent, ColumnsDirective, ColumnDirective } from '@syncfusion/ej2-react-querybuilder';
import * as React from 'react';
import * as ReactDom from 'react-dom';
import { PaymentTemplate } from './payment-temp';
import { TransactionTemplate } from './transaction-temp';
function App() {
    let qryBldrObj;
    let importRules = {
        'condition': 'and',
        'rules': [{
                'label': 'Transaction Type',
                'field': 'TransactionType',
                'type': 'string',
                'operator': 'equal',
                'value': 'Expense'
            },
            {
                'label': 'Payment Mode',
                'field': 'PaymentMode',
                'type': 'string',
                'operator': 'equal',
                'value': 'Cash'
            }]
    };
    function paymentTemplate(props) {
        return (<PaymentTemplate {...props}/>);
    }
    function transactionTemplate(props) {
        return (<TransactionTemplate {...props}/>);
    }
    return (<div>
        <QueryBuilderComponent width='100%' rule={importRules} id='querybuilder'>
            <ColumnsDirective>
                <ColumnDirective field="Category" label="Category" type="string"/>
                <ColumnDirective field="PaymentMode" label="PaymentMode" type="string" template={paymentTemplate}/>
                <ColumnDirective field="TransactionType" label="TransactionType" type="string" template={transactionTemplate}/>
                <ColumnDirective field="Description" label="Description" type="string"/>
                <ColumnDirective field="Date" label="Date" type="string"/>
                <ColumnDirective field="Amount" label="Amount" type="string"/>
            </ColumnsDirective>
        </QueryBuilderComponent>
    </div>);
}
export default App;
ReactDom.render(<App />, document.getElementById('querybuilder-component'));
import { QueryBuilderComponent, ColumnsDirective, ColumnDirective  } from '@syncfusion/ej2-react-querybuilder';
import { RuleModel } from '@syncfusion/ej2-querybuider';
import * as React from 'react';
import * as ReactDom from 'react-dom';
import { PaymentTemplate } from './payment-temp';
import { TransactionTemplate } from './transaction-temp';
function App() {
    let qryBldrObj: QueryBuilderComponent;
    let importRules: RuleModel = {
             'condition': 'and',
            'rules': [{
                'label': 'Transaction Type',
                'field': 'TransactionType',
                'type': 'string',
                'operator': 'equal',
                'value': 'Expense'
            },
            {
                'label': 'Payment Mode',
                'field': 'PaymentMode',
                'type': 'string',
                'operator': 'equal',
                'value': 'Cash'
            }]
    };
    function paymentTemplate(props) {
        return (<PaymentTemplate {...props}/>);
    }
    function transactionTemplate(props) {
        return (<TransactionTemplate {...props}/>);
    }
    return (<div>
        <QueryBuilderComponent width='100%' rule={importRules}  id='querybuilder'  >
            <ColumnsDirective>
                <ColumnDirective field="Category" label="Category" type="string"/>
                <ColumnDirective field="PaymentMode" label="PaymentMode" type="string" template = {paymentTemplate}/>
                <ColumnDirective field="TransactionType" label="TransactionType" type="string" template = {transactionTemplate}/>
                <ColumnDirective field="Description" label="Description" type="string"/>
                <ColumnDirective field="Date" label="Date" type="string"/>
                <ColumnDirective field="Amount" label="Amount" type="string"/>
            </ColumnsDirective>
        </QueryBuilderComponent>
    </div>);
}
export default App;
ReactDom.render(<App />,document.getElementById('querybuilder-component'));
import * as React from 'react';
import { DropDownListComponent } from '@syncfusion/ej2-react-dropdowns';
import { getComponent } from '@syncfusion/ej2-base';
export function PaymentTemplate(props) {
    let ds = ['Cash', 'Debit Card', 'Credit Card', 'Net Banking'];
    let qryBldrObj;
    let state = Object.assign({}, props);
    qryBldrObj = getComponent(document.getElementById('querybuilder'), 'query-builder');
    const args = state;
    function paymentChange(event) {
        const args = state;
        let elem = document.getElementById(args.ruleID).querySelector('.e-rule-value');
        qryBldrObj.notifyChange(event.value, elem, 'value');
    }
    return (<div>
        <DropDownListComponent dataSource={ds} value={args.rule.value} change={paymentChange}/>
        </div>);
}
import * as React from 'react';
import { DropDownListComponent } from '@syncfusion/ej2-react-dropdowns';
import { getComponent,  closest } from '@syncfusion/ej2-base';
import { QueryBuilderComponent } from '@syncfusion/ej2-react-querybuider';
import { QueryBuilder, ActionEventArgs, RuleModel } from '@syncfusion/ej2-querybuider';


export function PaymentTemplate(props) {
    let ds: string[] = ['Cash', 'Debit Card', 'Credit Card', 'Net Banking'];
    let qryBldrObj: QueryBuilderComponent;

    let state = Object.assign({}, props);
    qryBldrObj = getComponent(document.getElementById('querybuilder'), 'query-builder') as QueryBuilder;
    const args: ActionEventArgs = state;
    function paymentChange(event: any): void{
        const args: ActionEventArgs = state;
        let elem: HTMLElement = document.getElementById(args.ruleID).querySelector('.e-rule-value');
        qryBldrObj.notifyChange(event.value as string, elem, 'value');
    }

    return (<div >
        <DropDownListComponent  dataSource={ds}  value={args.rule.value} change={paymentChange}/>
        </div>
    );
}
import * as React from 'react';
import { getComponent } from '@syncfusion/ej2-base';
import { CheckBoxComponent } from '@syncfusion/ej2-react-buttons';
export function TransactionTemplate(props) {
    let qryBldrObj;
    let state = Object.assign({}, props);
    qryBldrObj = getComponent(document.getElementById('querybuilder'), 'query-builder');
    const args = state;
    function transactionChange(event) {
        const args = state;
        let elem = document.getElementById(args.ruleID).querySelector('.e-rule-value');
        qryBldrObj.notifyChange(event.checked === true ? 'Expense' : 'Income', elem, 'value');
    }
    return (<div>
            <CheckBoxComponent label="Is Expense" checked={args.rule.value} change={transactionChange}/>     
        </div>);
}
import * as React from 'react';
import { getComponent,  closest } from '@syncfusion/ej2-base';
import { CheckBoxComponent, ButtonComponent} from '@syncfusion/ej2-react-buttons';
import { QueryBuilderComponent } from '@syncfusion/ej2-react-querybuider';
import { QueryBuilder, ActionEventArgs, RuleModel } from '@syncfusion/ej2-querybuider';


export function TransactionTemplate(props) {
    let qryBldrObj: QueryBuilderComponent;

    let state = Object.assign({}, props);
    qryBldrObj = getComponent(document.getElementById('querybuilder'), 'query-builder') as QueryBuilder;
    const args: ActionEventArgs = state;
    function transactionChange(event: any): void{
        const args: ActionEventArgs = state;
        let elem: HTMLElement = document.getElementById(args.ruleID).querySelector('.e-rule-value');
        qryBldrObj.notifyChange(event.checked === true ? 'Expense' : 'Income', elem, 'value');
    }

    return (<div>
            <CheckBoxComponent  label="Is Expense" checked={args.rule.value}  change={transactionChange}/>     
        </div>
    );
}

Rule Template

Rule Template allows to define your own user interface for columns. To implement ruleTemplate, you can create the user interface as React component and assign the values through actionBegin event.

In the following sample, dropdown and slider are used as the custom component and applied greaterthanorequal operator to Age column.

import { QueryBuilderComponent, ColumnsDirective, ColumnDirective } from '@syncfusion/ej2-react-querybuilder';
import * as React from 'react';
import * as ReactDom from 'react-dom';
// @ts-ignore
import { employeeData } from '../datasource.ts';
import { AgeTemplate } from './template';
function App() {
    let qryBldrObj;
    let elem;
    let importRules = {
        'condition': 'or',
        'rules': [{
                'field': 'Age',
                'label': 'Age',
                'operator': 'greaterthanorequal',
                'type': 'number',
                'value': 30
            }]
    };
    function ageTemplate(props) {
        return (<AgeTemplate {...props}/>);
    }
    function actionBegin(args) {
        let ruleID = args.ruleID;
        args.rule.operator = 'greaterthanorequal';
        if (args.requestType === 'template-initialize') {
            if (args.rule.value === '') {
                args.rule.value = 30;
            }
        }
    }
    return (<QueryBuilderComponent dataSource={employeeData} width='100%' rule={importRules} ref={(scope) => { qryBldrObj = scope; }} actionBegin={actionBegin} id='querybuilder'>
            <ColumnsDirective>
                <ColumnDirective field="EmployeeID" label="Employee ID" type="number"/>
                <ColumnDirective field="LastName" label="Last Name" type="string"/>
                <ColumnDirective field="FirstName" label="First Name" type="string"/>
                <ColumnDirective field="Age" label="Age" type="number" ruleTemplate={ageTemplate}/>
                <ColumnDirective field="City" label="City" type="string"/>
                <ColumnDirective field="Country" label="Country" type="string"/>
            </ColumnsDirective>
        </QueryBuilderComponent>);
}
export default App;
ReactDom.render(<App />, document.getElementById('querybuilder-component'));
import { getComponent, setValue } from '@syncfusion/ej2-base';
import { ChangeEventArgs, DropDownList } from '@syncfusion/ej2-react-dropdowns';
import { QueryBuilderComponent, ColumnsDirective, ColumnDirective, RuleModel, ActionEventArgs } from '@syncfusion/ej2-react-querybuilder';
import * as React from 'react';
import * as ReactDom from 'react-dom';
// @ts-ignore
import { employeeData } from '../datasource.ts';
import { AgeTemplate } from './template';

function App() {
    let qryBldrObj: QueryBuilderComponent;
    let elem: HTMLElement;

    let importRules: RuleModel = {
            'condition': 'or',
            'rules': [{
                'field': 'Age',
                'label': 'Age',
                'operator': 'greaterthanorequal',
                'type': 'number',
                'value': 30
            }]
    };

    function ageTemplate(props): any {
      return (<AgeTemplate {...props} />);
    }

    function actionBegin(args: ActionEventArgs): void {
      let ruleID = args.ruleID;
      args.rule.operator = 'greaterthanorequal';
      if (args.requestType === 'template-initialize') {
        if (args.rule.value === '') {
          args.rule.value = 30;
        }
      }
    }

    return (
        <QueryBuilderComponent dataSource={employeeData} width='100%' rule={importRules} ref={(scope) => { qryBldrObj = scope as QueryBuilderComponent; }} actionBegin={actionBegin} id='querybuilder'>
            <ColumnsDirective>
                <ColumnDirective field="EmployeeID" label="Employee ID" type="number"/>
                <ColumnDirective field="LastName" label="Last Name" type="string"/>
                <ColumnDirective field="FirstName" label="First Name" type="string"/>
                <ColumnDirective field="Age" label="Age" type="number" ruleTemplate={ageTemplate}/>
                <ColumnDirective field="City" label="City" type="string"/>
                <ColumnDirective field="Country" label="Country" type="string"/>
            </ColumnsDirective>
        </QueryBuilderComponent>
    );
}
export default App;
ReactDom.render(<App />,document.getElementById('querybuilder-component'));
import * as React from 'react';
import { SliderComponent } from '@syncfusion/ej2-react-inputs';
import { DropDownListComponent } from '@syncfusion/ej2-react-dropdowns';
import { getComponent, compile } from '@syncfusion/ej2-base';
import { DataManager, Query } from '@syncfusion/ej2-data';
import { employeeData } from '../datasource.ts';
export function AgeTemplate(props) {
    let qryBldrObj;
    let sliderObj;
    let rangeTicks = { placement: 'Before', largeStep: 5, showSmallTicks: true };
    let state = Object.assign({}, props);
    qryBldrObj = getComponent(document.getElementById('querybuilder'), 'query-builder');
    function fieldChange(args) {
        qryBldrObj.notifyChange(args.value, args.element, 'field');
    }
    function valueChange(args) {
        let elem = sliderObj.element;
        qryBldrObj.notifyChange(args.value, elem, 'value');
        refreshTable(qryBldrObj.getRule(elem), elem.id.split('_valuekey0')[0]);
    }
    function sliderCreated() {
        let elem = sliderObj.element;
        refreshTable(qryBldrObj.getRule(elem), elem.id.split('_valuekey0')[0]);
    }
    function myFunction(ruleID) {
        let element = document.getElementById(ruleID + '_section');
        if (element.className.indexOf('e-hide') > -1) {
            element.className = element.className.replace('e-hide', '');
            document.getElementById(ruleID + '_option').textContent = 'Hide Details';
        }
        else {
            element.className += ' e-hide';
            document.getElementById(ruleID + '_option').textContent = 'View Details';
        }
    }
    function refreshTable(rule, ruleID) {
        let template = '<tr><td>${EmployeeID}</td><td>${FirstName}</td><td>${Age}</td></tr>';
        let compiledFunction = compile(template);
        let predicate = qryBldrObj.getPredicate({ condition: 'and', rules: [rule] });
        let dataManagerQuery = new Query().select(['EmployeeID', 'FirstName', 'Age']).where(predicate);
        let result = new DataManager(employeeData).executeLocal(dataManagerQuery);
        let table = document.getElementById(ruleID + '_datatable');
        if (result.length) {
            table.style.display = 'block';
        }
        else {
            table.style.display = 'none';
        }
        table.querySelector('tbody').innerHTML = '';
        result.forEach((data) => {
            table.querySelector('tbody').appendChild(compiledFunction(data)[0].querySelector('tr'));
        });
    }
    const args = state;
    return (<div className="e-rule e-rule-template">
          <div className="e-rule-filter e-custom-filter">
            <DropDownListComponent change={fieldChange} fields={args.fields} dataSource={args.columns} value={args.rule.field}/>
          </div>
    <div>
      <div className="e-slider-value">
        <SliderComponent ticks={rangeTicks} ref={(scope) => { sliderObj = scope; }} id={args.ruleID + '_valuekey0'} change={valueChange} created={sliderCreated} value={args.rule.value} min={30} max={50}/>
      </div>
      <div className="e-rule-btn">
        <button id={args.ruleID + '_option'} onClick={myFunction.bind(this, args.ruleID)} className="e-primary e-btn e-small">
          View Details
        </button>
        <button className="e-removerule e-rule-delete e-css e-btn e-small e-round">
          <span className="e-btn-icon e-icons e-delete-icon"/>
        </button>
      </div>
    </div>
          <div id={args.ruleID + '_section'} className="e-rule-value-group e-hide">
              <div>
                  <table id={args.ruleID + '_datatable'} className='e-rule-table e-hide'>
                      <thead>
                          <tr><th>EmployeeID</th><th>FirstName</th><th>Age</th></tr>
                      </thead>
                      <tbody>
                      </tbody>
                  </table>     
              </div>
          </div>
        </div>);
}
import * as React from 'react';
import { SliderComponent } from '@syncfusion/ej2-react-inputs';
import { DropDownListComponent } from '@syncfusion/ej2-react-dropdowns';
import { getComponent, compile } from '@syncfusion/ej2-base';
import { DataManager, Predicate, Query } from '@syncfusion/ej2-data';
import { QueryBuilderComponent } from '@syncfusion/ej2-react-querybuider';
import { QueryBuilder, ActionEventArgs, RuleModel } from '@syncfusion/ej2-querybuider';
import { employeeData } from '../datasource.ts';

export function AgeTemplate(props) {
  let qryBldrObj: QueryBuilderComponent;
  let sliderObj: SliderComponent;
  let rangeTicks: object = { placement: 'Before', largeStep: 5, showSmallTicks: true };
  let state = Object.assign({}, props);
  qryBldrObj = getComponent(document.getElementById('querybuilder'), 'query-builder') as QueryBuilder;

    function fieldChange(args: any): void {
      qryBldrObj.notifyChange(args.value, args.element, 'field');
    }

    function valueChange(args: any): void {
        let elem: Element = sliderObj.element;
        qryBldrObj.notifyChange(args.value, elem, 'value');
        refreshTable(qryBldrObj.getRule(elem), elem.id.split('_valuekey0')[0]);
    }

    function sliderCreated() {
        let elem: Element = sliderObj.element;
        refreshTable(qryBldrObj.getRule(elem), elem.id.split('_valuekey0')[0]);
    }

    function myFunction(ruleID: string): void {
      let element: Element = document.getElementById(ruleID + '_section');
      if (element.className.indexOf('e-hide') > -1) {
          element.className = element.className.replace('e-hide', '');
          document.getElementById(ruleID + '_option').textContent = 'Hide Details';
      } else {
          element.className += ' e-hide';
          document.getElementById(ruleID + '_option').textContent = 'View Details';
      }
    }

    function refreshTable(rule: RuleModel, ruleID: string): void {
      let template: string = '<tr><td>${EmployeeID}</td><td>${FirstName}</td><td>${Age}</td></tr>';
      let compiledFunction: any = compile(template);
      let predicate: Predicate = qryBldrObj.getPredicate({condition: 'and', rules: [rule]});
      let dataManagerQuery: Query = new Query().select(['EmployeeID', 'FirstName', 'Age']).where(predicate);
      let result: object[] = new DataManager(employeeData).executeLocal(dataManagerQuery);
      let table: HTMLElement = document.getElementById(ruleID + '_datatable') as HTMLElement;
      if (result.length) {
        table.style.display = 'block';
      } else {
        table.style.display = 'none';
      }
      table.querySelector('tbody').innerHTML = '';
      result.forEach((data) => {
          table.querySelector('tbody').appendChild(compiledFunction(data)[0].querySelector('tr'));
      });
    }
    const args: ActionEventArgs = state;
      return (
        <div className="e-rule e-rule-template">
          <div className="e-rule-filter e-custom-filter">
            <DropDownListComponent change={fieldChange} fields={args.fields} dataSource={args.columns} value={args.rule.field}/>
          </div>
    <div>
      <div className="e-slider-value">
        <SliderComponent ticks={rangeTicks} ref={(scope) => { sliderObj = scope as SliderComponent; }} id={args.ruleID + '_valuekey0'} change={valueChange} created={sliderCreated} value={args.rule.value} min={30} max={50} />
      </div>
      <div className="e-rule-btn">
        <button id={args.ruleID + '_option'} onClick={myFunction.bind(this, args.ruleID)} className="e-primary e-btn e-small">
          View Details
        </button>
        <button className="e-removerule e-rule-delete e-css e-btn e-small e-round">
          <span className="e-btn-icon e-icons e-delete-icon"/>
        </button>
      </div>
    </div>
          <div id={args.ruleID + '_section'} className="e-rule-value-group e-hide">
              <div>
                  <table id={args.ruleID + '_datatable'} className='e-rule-table e-hide'>
                      <thead>
                          <tr><th>EmployeeID</th><th>FirstName</th><th>Age</th></tr>
                      </thead>
                      <tbody>
                      </tbody>
                  </table>     
              </div>
          </div>
        </div>
      );
}