Search results

Templates in React QueryBuilder component

09 Jun 2021 / 6 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.

Source
Preview
app.tsx
template.tsx
index.html
app.jsx
template.jsx
Copied to clipboard
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';

class App extends React.Component {
    public qryBldrObj: QueryBuilderComponent;
    public 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
                    }]
                }
            ]
        };
    public headerTemplate(props): any {
        return (<HeaderTemplate {...props}/>);
    }
    public render() {
        return (<div>
            <QueryBuilderComponent width='100%' rule={this.importRules} headerTemplate= {this.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>);
    }
}
ReactDom.render(<App />,document.getElementById('querybuilder-component'));
Copied to clipboard
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 class HeaderTemplate extends React.Component {
 public ds: { [key: string]: Object }[] = [{'key': 'AND', 'value': 'and'},{'key': 'OR', 'value': 'or'}];
 public qryBldrObj: QueryBuilderComponent;
 public fields: object = { text: 'key', value: 'value'};
 public ddbitems: ItemModel[] = [
    {
        text: 'AddGroup',
        iconCss: 'e-icons e-add-icon e-addgroup'
    },
    {
        text: 'AddCondition',
        iconCss: 'e-icons e-add-icon e-addrule'
    }];
 constructor(props: object) {
    super(props);
        this.state = Object.assign({}, props);
        this.qryBldrObj = getComponent(document.getElementById('querybuilder'), 'query-builder') as QueryBuilder;
    }
    public onChange(args: any): void{
        this.qryBldrObj.notifyChange(args.checked, args.event.target, 'not');
    }
    public conditionChange(args: any): void{
        this.qryBldrObj.notifyChange(args.value, args.element, 'condition');
    }
    public 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') {
            this.qryBldrObj.addGroups([{condition: 'or', 'rules': [{}], not: false}], ddb[1]);
        } else if (event.item.text === 'AddCondition') {
            this.qryBldrObj.addRules([{}], ddb[1]);
        }
    }
    public onClick(args: any): void{
        this.qryBldrObj.deleteGroup(closest(args.target.offsetParent, '.e-group-container'));
    }
    public render() {
        const args: ActionEventArgs = this.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={this.onChange.bind(this)}/>
                    </button>);
                }
            })()}
            <DropDownListComponent id = {args.ruleID + "_cndtn"} cssClass = 'e-custom-group-btn' dataSource={this.ds}  fields={this.fields}  value={args.condition} change={this.conditionChange.bind(this)}/>
            <DropDownButtonComponent id = {args.ruleID + "_addbtn"} items={this.ddbitems} cssClass= "e-round e-small e-caret-hide e-addrulegroup e-add-btn" iconCss="e-icons e-add-icon" select={this.onSelect.bind(this)}></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={this.onClick.bind(this)} ></ButtonComponent>)
                }
            })()}
			</div>
		);
    }
}
Copied to clipboard
<!DOCTYPE html>
<html lang="en">

<head>
    <title>Syncfusion React Query Builder</title>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta name="description" content="Essential JS 2 for React Components" />
    <meta name="author" content="Syncfusion" />
    <link href="//cdn.syncfusion.com/ej2/ej2-base/styles/material.css" rel="stylesheet" />
    <link href="//cdn.syncfusion.com/ej2/ej2-buttons/styles/material.css" rel="stylesheet" />
    <link href="//cdn.syncfusion.com/ej2/ej2-splitbuttons/styles/material.css" rel="stylesheet" />
    <link href="//cdn.syncfusion.com/ej2/ej2-dropdowns/styles/material.css" rel="stylesheet" />
    <link href="//cdn.syncfusion.com/ej2/ej2-inputs/styles/material.css" rel="stylesheet" />
    <link href="//cdn.syncfusion.com/ej2/ej2-calendars/styles/material.css" rel="stylesheet" />
    <link href="//cdn.syncfusion.com/ej2/ej2-popups/styles/material.css" rel="stylesheet" />
    <link href="//cdn.syncfusion.com/ej2/ej2-querybuilder/styles/material.css" rel="stylesheet" />
	<link href="index.css" rel="stylesheet" />
    <script src="https://cdnjs.cloudflare.com/ajax/libs/systemjs/0.19.38/system.js"></script>
    <script src="systemjs.config.js"></script>
</head>

<body>
        <div id='querybuilder-component'>
            <div id='loader'>Loading....</div>
        </div>
</body>

</html>
Copied to clipboard
import { QueryBuilderComponent, ColumnsDirective, ColumnDirective } from '@syncfusion/ej2-react-querybuilder';
import * as React from 'react';
import * as ReactDom from 'react-dom';
import { HeaderTemplate } from './template';
class App extends React.Component {
    constructor() {
        super(...arguments);
        this.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
                        }]
                }
            ]
        };
    }
    headerTemplate(props) {
        return (<HeaderTemplate {...props}/>);
    }
    render() {
        return (<div>
            <QueryBuilderComponent width='100%' rule={this.importRules} headerTemplate={this.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>);
    }
}
ReactDom.render(<App />, document.getElementById('querybuilder-component'));
Copied to clipboard
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 class HeaderTemplate extends React.Component {
    constructor(props) {
        super(props);
        this.ds = [{ 'key': 'AND', 'value': 'and' }, { 'key': 'OR', 'value': 'or' }];
        this.fields = { text: 'key', value: 'value' };
        this.ddbitems = [
            {
                text: 'AddGroup',
                iconCss: 'e-icons e-add-icon e-addgroup'
            },
            {
                text: 'AddCondition',
                iconCss: 'e-icons e-add-icon e-addrule'
            }
        ];
        this.state = Object.assign({}, props);
        this.qryBldrObj = getComponent(document.getElementById('querybuilder'), 'query-builder');
    }
    onChange(args) {
        this.qryBldrObj.notifyChange(args.checked, args.event.target, 'not');
    }
    conditionChange(args) {
        this.qryBldrObj.notifyChange(args.value, args.element, 'condition');
    }
    onSelect(event) {
        let addbtn = closest(event.element, '.e-dropdown-popup');
        let ddbId = addbtn.id;
        let ddb = ddbId.split('_');
        if (event.item.text === 'AddGroup') {
            this.qryBldrObj.addGroups([{ condition: 'or', 'rules': [{}], not: false }], ddb[1]);
        }
        else if (event.item.text === 'AddCondition') {
            this.qryBldrObj.addRules([{}], ddb[1]);
        }
    }
    onClick(args) {
        this.qryBldrObj.deleteGroup(closest(args.target.offsetParent, '.e-group-container'));
    }
    render() {
        const args = this.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={this.onChange.bind(this)}/>
                    </button>);
            }
        })()}
            <DropDownListComponent id={args.ruleID + "_cndtn"} cssClass='e-custom-group-btn' dataSource={this.ds} fields={this.fields} value={args.condition} change={this.conditionChange.bind(this)}/>
            <DropDownButtonComponent id={args.ruleID + "_addbtn"} items={this.ddbitems} cssClass="e-round e-small e-caret-hide e-addrulegroup e-add-btn" iconCss="e-icons e-add-icon" select={this.onSelect.bind(this)}></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={this.onClick.bind(this)}></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.

Source
Preview
app.tsx
index.html
datasource.ts
app.jsx
Copied to clipboard
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';

class App extends React.Component<{}, {}> {
public qryBldrObj: QueryBuilderComponent;
public elem: HTMLElement;
public dropDownObj: DropDownList;
public multiSelectObj: MultiSelect;
public inOperators: string [] = ['in', 'notin'];
public 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: () => {
                this.elem = document.createElement('input');
                this.elem.setAttribute('type', 'text');
                return this.elem;
            },
            destroy: (args: { elementId: string }) => {
                this.multiSelectObj = getComponent(document.getElementById(args.elementId) as HTMLElement, 'multiselect') as MultiSelect;
                if (this.multiSelectObj) {
                    this.multiSelectObj.destroy();
                }
                this.dropDownObj = getComponent(document.getElementById(args.elementId) as HTMLElement, 'dropdownlist') as DropDownList;
                if (this.dropDownObj) {
                    this.dropDownObj.destroy();
                }
            },
            write: (args: { elements: Element, values: string[] | string, operator: string }) => {
                const ds = ['Cash', 'Debit Card', 'Credit Card', 'Net Banking', 'Wallet'];
                if (this.inOperators.indexOf(args.operator) > -1) {
                    this.multiSelectObj = new MultiSelect({
                        change: (e: MultiSelectChangeEventArgs) => {
                            this.qryBldrObj.notifyChange(e.value as string[], e.element);
                        },
                        dataSource: ds,
                        mode: 'CheckBox',
                        placeholder: 'Select Transaction',
                        value: args.values as string []
                    });
                    this.multiSelectObj.appendTo('#' + args.elements.id);
                } else {
                    this.dropDownObj = new DropDownList({
                        change: (e: ChangeEventArgs) => {
                            this.qryBldrObj.notifyChange(e.itemData.value as string, e.element);
                        },
                        dataSource: ds,
                        value: args.values ? args.values as string : ds[0]
                    });
                    this.dropDownObj.appendTo('#' + args.elements.id);
                }
            }
        }, type: 'string'
    },
    { field: 'Description', label: 'Description', type: 'string' },
    { field: 'Date', label: 'Date', type: 'date' }
];

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

public render() {
    return (
        <QueryBuilderComponent dataSource={expenseData} columns={this.filter} width='100%' rule={this.importRules} ref={(scope) => { this.qryBldrObj = scope as QueryBuilderComponent; }} />
    );
}
}

ReactDom.render(<App />,document.getElementById('querybuilder'));
Copied to clipboard
<!DOCTYPE html>
<html lang="en">

<head>
    <title>Syncfusion React Query Builder</title>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta name="description" content="Essential JS 2 for React Components" />
    <meta name="author" content="Syncfusion" />
    <link href="//cdn.syncfusion.com/ej2/ej2-base/styles/material.css" rel="stylesheet" />
    <link href="//cdn.syncfusion.com/ej2/ej2-buttons/styles/material.css" rel="stylesheet" />
    <link href="//cdn.syncfusion.com/ej2/ej2-splitbuttons/styles/material.css" rel="stylesheet" />
    <link href="//cdn.syncfusion.com/ej2/ej2-dropdowns/styles/material.css" rel="stylesheet" />
    <link href="//cdn.syncfusion.com/ej2/ej2-inputs/styles/material.css" rel="stylesheet" />
    <link href="//cdn.syncfusion.com/ej2/ej2-calendars/styles/material.css" rel="stylesheet" />
    <link href="//cdn.syncfusion.com/ej2/ej2-popups/styles/material.css" rel="stylesheet" />
    <link href="//cdn.syncfusion.com/ej2/ej2-querybuilder/styles/material.css" rel="stylesheet" />
	<link href="index.css" rel="stylesheet" />
    <script src="https://cdnjs.cloudflare.com/ajax/libs/systemjs/0.19.38/system.js"></script>
    <script src="systemjs.config.js"></script>
</head>

<body>
        <div id='querybuilder'>
            <div id='loader'>Loading....</div>
        </div>
</body>

</html>
Copied to clipboard
/**
 * QueryBuilder datasource
 */
export let employeeData: Array<{[key: string]: any}> = [
	{
		'Address': '507 - 20th Ave. E.\r\nApt. 2A',
		'City': 'Seattle',
		'Country': 'USA',
		'EmployeeID': 1,
		'FirstName': 'Nancy',
		'HireDate': '22/07/2001',
		'LastName': 'Davolio',
		'PostalCode': '98122',
		'Region': 'WA',
		'Title': 'Sales Representative',
		'TitleOfCourtesy': 'Ms.'
	},
	{
		'Address': '908 W. Capital Way',
		'City': 'Tacoma',
		'Country': 'USA',
		'EmployeeID': 2,
		'FirstName': 'Andrew',
		'HireDate': '21/04/2003',
		'LastName': 'Fuller',
		'PostalCode': '98401',
		'Region': 'WA',
		'Title': 'Vice President',
		'TitleOfCourtesy': 'Dr.'
	},
	{
		'Address': '722 Moss Bay Blvd.',
		'City': 'Kirkland',
		'Country': 'USA',
		'EmployeeID': 3,
		'FirstName': 'Janet',
		'HireDate': '22/07/2001',
		'LastName': 'Leverling',
		'PostalCode': '98033',
		'Region': 'WA',
		'Title': 'Sales Representative',
		'TitleOfCourtesy': 'Ms.'
	},
	{
		'Address': '4110 Old Redmond Rd.',
		'City': 'Redmond',
		'Country': 'USA',
		'EmployeeID': 4,
		'FirstName': 'Margaret',
		'HireDate': '22/07/2004',
		'LastName': 'Peacock',
		'PostalCode': '98052',
		'Region': 'WA',
		'Title': 'Sales Representative',
		'TitleOfCourtesy': 'Mrs.'
	},
	{
		'Address': '14 Garrett Hill',
		'City': 'London',
		'Country': 'UK',
		'EmployeeID': 5,
		'FirstName': 'Steven',
		'HireDate': '02/04/2001',
		'LastName': 'Buchanan',
		'PostalCode': 'SW1 8JR',
		'Region': null,
		'Title': 'Sales Manager',
		'TitleOfCourtesy': 'Mr.'
	},
	{
		'Address': 'Coventry House\r\nMiner Rd.',
		'City': 'London',
		'Country': 'UK',
		'EmployeeID': 6,
		'FirstName': 'Michael',
		'HireDate': '22/01/2003',
		'LastName': 'Suyama',
		'PostalCode': 'EC2 7JR',
		'Region': null,
		'Title': 'Sales Representative',
		'TitleOfCourtesy': 'Mr.'
	},
	{
		'Address': 'Edgeham Hollow\r\nWinchester Way',
		'City': 'London',
		'Country': 'UK',
		'EmployeeID': 7,
		'FirstName': 'Robert',
		'HireDate': '22/07/2001',
		'LastName': 'King',
		'PostalCode': 'RG1 9SP',
		'Region': null,
		'Title': 'Sales Representative',
		'TitleOfCourtesy': 'Mr.'
	},
	{
		'Address': '4726 - 11th Ave. N.E.',
		'City': 'Seattle',
		'Country': 'USA',
		'EmployeeID': 8,
		'FirstName': 'Laura',
		'HireDate': '22/07/2001',
		'LastName': 'Callahan',
		'PostalCode': '98105',
		'Region': 'WA',
		'Title': 'Inside Sales Coordinator',
		'TitleOfCourtesy': 'Ms.'
	},
	{
		'Address': '7 Houndstooth Rd.',
		'City': 'London',
		'Country': 'UK',
		'EmployeeID': 9,
		'FirstName': 'Anne',
		'HireDate': '22/07/2001',
		'LastName': 'Dodsworth',
		'PostalCode': 'WG2 7LT',
		'Region': null,
		'Title': 'Sales Representative',
		'TitleOfCourtesy': 'Ms.'
	}
];
export let expenseData: Array<{[key: string]: any}>  = [
	{
		'Amount': '7',
		'Category': 'Food',
		'Description': 'Boiled peanuts',
		'FormattedDate': '06/01/2017 09:12 AM',
		'MonthFull': 'June, 2017',
		'MonthShort': 'Jun',
		'PaymentMode': 'Credit Card',
		'TransactionType': 'Expense',
		'UniqueId': 'T100001'
	},
	{
		'Amount': '8',
		'Category': 'Food',
		'Description': 'Peanuts in Coke',
		'FormattedDate': '06/04/2017 02:43 PM',
		'MonthFull': 'June, 2017',
		'MonthShort': 'Jun',
		'PaymentMode': 'Cash',
		'TransactionType': 'Expense',
		'UniqueId': 'T100024'
	},
	{
		'Amount': '11',
		'Category': 'Food',
		'Description': 'Palmetto Cheese, Mint julep',
		'FormattedDate': '06/04/2017 08:35 PM',
		'MonthFull': 'June, 2017',
		'MonthShort': 'Jun',
		'PaymentMode': 'Cash',
		'TransactionType': 'Expense',
		'UniqueId': 'T100025'
	},
	{
		'Amount': '9',
		'Category': 'Transportation',
		'Description': 'Cars and trucks, used',
		'FormattedDate': '06/04/2017 10:25 AM',
		'MonthFull': 'June, 2017',
		'MonthShort': 'Jun',
		'PaymentMode': 'Debit Card',
		'TransactionType': 'Expense',
		'UniqueId': 'T100026'
	},
	{
		'Amount': '8',
		'Category': 'Transportation',
		'Description': 'Public and other transportation',
		'FormattedDate': '06/04/2017 03:55 PM',
		'MonthFull': 'June, 2017',
		'MonthShort': 'Jun',
		'PaymentMode': 'Debit Card',
		'TransactionType': 'Expense',
		'UniqueId': 'T100027'
	},
	{
		'Amount': '160',
		'Category': 'Shopping',
		'Description': 'Household things & Utilities',
		'FormattedDate': '06/04/2017 10:22 AM',
		'MonthFull': 'June, 2017',
		'MonthShort': 'Jun',
		'PaymentMode': 'Cash',
		'TransactionType': 'Expense',
		'UniqueId': 'T100028'
	},
	{
		'Amount': '110',
		'Category': 'Extra income',
		'Description': 'Income from Sale',
		'FormattedDate': '11/30/2017 02:42 PM',
		'MonthFull': 'November, 2017',
		'MonthShort': 'Nov',
		'PaymentMode': 'Cash',
		'TransactionType': 'Income',
		'UniqueId': 'T101284'
	}
];
export let hardwareData: Array<{[key: string]: any}>  = [
	{
		'AssignedTo': 'John Doe',
		'Category': 'Laptop',
		'DOP': '04/10/2018',
		'InvoiceNo': 'INV-2878',
		'Name': 'Lenovo Yoga',
		'Note': 'Remarks are noted',
		'SerialNo': 'CB27932009',
		'Status': 'Assigned',
		'TaskID': 1,
		'WEO': '05/01/2021'
	},
	{
		'AssignedTo': '',
		'Category': 'Others',
		'DOP': '02/12/2018',
		'InvoiceNo': 'INV-3456',
		'Name': 'Acer Aspire',
		'Note': 'Remarks are noted',
		'SerialNo': 'CB35728290',
		'Status': 'In-repair',
		'TaskID': 2,
		'WEO': '03/01/2023'
	},
	{
		'AssignedTo': '',
		'Category': 'Laptop',
		'DOP': '04/10/2018',
		'InvoiceNo': 'INV-2763',
		'Name': 'Apple MacBook',
		'Note': 'Remarks are noted',
		'SerialNo': 'CB35628728',
		'Status': 'In-repair',
		'TaskID': 3,
		'WEO': '04/03/2021'
	},
	{
		'AssignedTo': '',
		'Category': 'Laptop',
		'DOP': '03/09/2018',
		'InvoiceNo': 'INV-2980',
		'Name': 'Lenovo ThinkPad',
		'Note': 'Remarks are noted',
		'SerialNo': 'CB56209872',
		'Status': 'Pending',
		'TaskID': 4,
		'WEO': '05/12/2021'
	},
	{
		'AssignedTo': 'David Anto',
		'Category': 'Laptop',
		'DOP': '01/10/2018',
		'InvoiceNo': 'INV-3782',
		'Name': 'Dell Inspiron',
		'Note': 'Remarks are noted',
		'SerialNo': 'CB56289036',
		'Status': 'Assigned',
		'TaskID': 5,
		'WEO': '04/01/2021'
	},
	{
		'AssignedTo': 'Mary Saveley',
		'Category': 'Laptop',
		'DOP': '04/10/2018',
		'InvoiceNo': 'INV-2712',
		'Name': 'HP Pavilion',
		'Note': 'Remarks are noted',
		'SerialNo': 'CB56289305',
		'Status': 'Assigned',
		'TaskID': 6,
		'WEO': '05/01/2021'
	},
	{
		'AssignedTo': '',
		'Category': 'Laptop',
		'DOP': '06/16/2018',
		'InvoiceNo': 'INV-0984',
		'Name': 'Asus ZenBook',
		'Note': 'Remarks are noted',
		'SerialNo': 'CB25637891',
		'Status': 'Pending',
		'TaskID': 7,
		'WEO': '09/01/2021'
	},
	{
		'AssignedTo': '',
		'Category': 'Laptop',
		'DOP': '02/19/2018',
		'InvoiceNo': 'INV-2561',
		'Name': 'HP EliteBook',
		'Note': 'Remarks are noted',
		'SerialNo': 'CB27819726',
		'Status': 'Ordered',
		'TaskID': 8,
		'WEO': '05/21/2021'
	},
	{
		'AssignedTo': '',
		'Category': 'Laptop',
		'DOP': '02/12/2018',
		'InvoiceNo': 'INV-8970',
		'Name': 'Apple MacBook Air',
		'Note': 'Remarks are noted',
		'SerialNo': 'CB05262880',
		'Status': 'Pending',
		'TaskID': 9,
		'WEO': '03/01/2023'
	},
	{
		'AssignedTo': '',
		'Category': 'Tablet',
		'DOP': '04/10/2018',
		'InvoiceNo': 'INV-4555',
		'Name': 'Apple iPad Air',
		'Note': 'Remarks are noted',
		'SerialNo': 'CB45262777',
		'Status': 'Pending',
		'TaskID': 10,
		'WEO': '05/01/2021'
	}
];
Copied to clipboard
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';
class App extends React.Component {
    constructor() {
        super(...arguments);
        this.inOperators = ['in', 'notin'];
        this.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: () => {
                        this.elem = document.createElement('input');
                        this.elem.setAttribute('type', 'text');
                        return this.elem;
                    },
                    destroy: (args) => {
                        this.multiSelectObj = getComponent(document.getElementById(args.elementId), 'multiselect');
                        if (this.multiSelectObj) {
                            this.multiSelectObj.destroy();
                        }
                        this.dropDownObj = getComponent(document.getElementById(args.elementId), 'dropdownlist');
                        if (this.dropDownObj) {
                            this.dropDownObj.destroy();
                        }
                    },
                    write: (args) => {
                        const ds = ['Cash', 'Debit Card', 'Credit Card', 'Net Banking', 'Wallet'];
                        if (this.inOperators.indexOf(args.operator) > -1) {
                            this.multiSelectObj = new MultiSelect({
                                change: (e) => {
                                    this.qryBldrObj.notifyChange(e.value, e.element);
                                },
                                dataSource: ds,
                                mode: 'CheckBox',
                                placeholder: 'Select Transaction',
                                value: args.values
                            });
                            this.multiSelectObj.appendTo('#' + args.elements.id);
                        }
                        else {
                            this.dropDownObj = new DropDownList({
                                change: (e) => {
                                    this.qryBldrObj.notifyChange(e.itemData.value, e.element);
                                },
                                dataSource: ds,
                                value: args.values ? args.values : ds[0]
                            });
                            this.dropDownObj.appendTo('#' + args.elements.id);
                        }
                    }
                }, type: 'string'
            },
            { field: 'Description', label: 'Description', type: 'string' },
            { field: 'Date', label: 'Date', type: 'date' }
        ];
        this.importRules = {
            'condition': 'or',
            'rules': [{
                    'field': 'PaymentMode',
                    'label': 'PaymentMode',
                    'operator': 'equal',
                    'type': 'string',
                    'value': 'Cash'
                }]
        };
    }
    render() {
        return (<QueryBuilderComponent dataSource={expenseData} columns={this.filter} width='100%' rule={this.importRules} ref={(scope) => { this.qryBldrObj = scope; }}/>);
    }
}
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.

Source
Preview
app.tsx
payment-temp.tsx
transaction-temp.tsx
index.html
app.jsx
payment-temp.jsx
transaction-temp.jsx
Copied to clipboard
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';

class App extends React.Component {
public qryBldrObj: QueryBuilderComponent;
public 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'
        }]
};
public paymentTemplate(props): any {
    return (<PaymentTemplate {...props}/>);
}
public transactionTemplate(props): any {
    return (<TransactionTemplate {...props}/>);
}
public render() {
    return (<div>
        <QueryBuilderComponent width='100%' rule={this.importRules}  id='querybuilder'  >
            <ColumnsDirective>
                <ColumnDirective field="Category" label="Category" type="string"/>
                <ColumnDirective field="PaymentMode" label="PaymentMode" type="string" operators ={this.customOperators} template = {this.paymentTemplate}/>
                <ColumnDirective field="TransactionType" label="TransactionType" type="string" operators ={this.customOperators} template = {this.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>);
}
}
ReactDom.render(<App />,document.getElementById('querybuilder-component'));
Copied to clipboard
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 class PaymentTemplate extends React.Component {
 public ds: string[] = ['Cash', 'Debit Card', 'Credit Card', 'Net Banking'];
 public qryBldrObj: QueryBuilderComponent;

 constructor(props: object) {
    super(props);
        this.state = Object.assign({}, props);
        this.qryBldrObj = getComponent(document.getElementById('querybuilder'), 'query-builder') as QueryBuilder;
    }
    
    public paymentChange(event: any): void{
        const args: ActionEventArgs = this.state;
        let elem: HTMLElement = document.getElementById(args.ruleID).querySelector('.e-rule-value');
        this.qryBldrObj.notifyChange(event.value as string, elem, 'value');
    }
    public render() {
        const args: ActionEventArgs = this.state;
        return (<div >
            <DropDownListComponent  dataSource={this.ds}  value={args.rule.value} change={this.paymentChange.bind(this)}/>
			</div>
		);
    }
}
Copied to clipboard
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 class TransactionTemplate extends React.Component {
 public qryBldrObj: QueryBuilderComponent;

 constructor(props: object) {
    super(props);
        this.state = Object.assign({}, props);
        this.qryBldrObj = getComponent(document.getElementById('querybuilder'), 'query-builder') as QueryBuilder;
    }
    
    public transactionChange(event: any): void{
        const args: ActionEventArgs = this.state;
        let elem: HTMLElement = document.getElementById(args.ruleID).querySelector('.e-rule-value');
        this.qryBldrObj.notifyChange(event.checked === true ? 'Expense' : 'Income', elem, 'value');
    }
    public render() {
        const args: ActionEventArgs = this.state;
        return (<div>
                <CheckBoxComponent  label="Is Expense" checked={args.rule.value}  change={this.transactionChange.bind(this)}/>     
			</div>
		);
    }
}
Copied to clipboard
<!DOCTYPE html>
<html lang="en">

<head>
    <title>Syncfusion React Query Builder</title>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta name="description" content="Essential JS 2 for React Components" />
    <meta name="author" content="Syncfusion" />
    <link href="//cdn.syncfusion.com/ej2/ej2-base/styles/material.css" rel="stylesheet" />
    <link href="//cdn.syncfusion.com/ej2/ej2-buttons/styles/material.css" rel="stylesheet" />
    <link href="//cdn.syncfusion.com/ej2/ej2-splitbuttons/styles/material.css" rel="stylesheet" />
    <link href="//cdn.syncfusion.com/ej2/ej2-dropdowns/styles/material.css" rel="stylesheet" />
    <link href="//cdn.syncfusion.com/ej2/ej2-inputs/styles/material.css" rel="stylesheet" />
    <link href="//cdn.syncfusion.com/ej2/ej2-calendars/styles/material.css" rel="stylesheet" />
    <link href="//cdn.syncfusion.com/ej2/ej2-popups/styles/material.css" rel="stylesheet" />
    <link href="//cdn.syncfusion.com/ej2/ej2-querybuilder/styles/material.css" rel="stylesheet" />
	<link href="index.css" rel="stylesheet" />
    <script src="https://cdnjs.cloudflare.com/ajax/libs/systemjs/0.19.38/system.js"></script>
    <script src="systemjs.config.js"></script>
</head>

<body>
        <div id='querybuilder-component'>
            <div id='loader'>Loading....</div>
        </div>
</body>

</html>
Copied to clipboard
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';
class App extends React.Component {
    constructor() {
        super(...arguments);
        this.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'
                }]
        };
    }
    paymentTemplate(props) {
        return (<PaymentTemplate {...props}/>);
    }
    transactionTemplate(props) {
        return (<TransactionTemplate {...props}/>);
    }
    render() {
        return (<div>
        <QueryBuilderComponent width='100%' rule={this.importRules} id='querybuilder'>
            <ColumnsDirective>
                <ColumnDirective field="Category" label="Category" type="string"/>
                <ColumnDirective field="PaymentMode" label="PaymentMode" type="string" operators={this.customOperators} template={this.paymentTemplate}/>
                <ColumnDirective field="TransactionType" label="TransactionType" type="string" operators={this.customOperators} template={this.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>);
    }
}
ReactDom.render(<App />, document.getElementById('querybuilder-component'));
Copied to clipboard
import * as React from 'react';
import { DropDownListComponent } from '@syncfusion/ej2-react-dropdowns';
import { getComponent } from '@syncfusion/ej2-base';
export class PaymentTemplate extends React.Component {
    constructor(props) {
        super(props);
        this.ds = ['Cash', 'Debit Card', 'Credit Card', 'Net Banking'];
        this.state = Object.assign({}, props);
        this.qryBldrObj = getComponent(document.getElementById('querybuilder'), 'query-builder');
    }
    paymentChange(event) {
        const args = this.state;
        let elem = document.getElementById(args.ruleID).querySelector('.e-rule-value');
        this.qryBldrObj.notifyChange(event.value, elem, 'value');
    }
    render() {
        const args = this.state;
        return (<div>
            <DropDownListComponent dataSource={this.ds} value={args.rule.value} change={this.paymentChange.bind(this)}/>
			</div>);
    }
}
Copied to clipboard
import * as React from 'react';
import { getComponent } from '@syncfusion/ej2-base';
import { CheckBoxComponent } from '@syncfusion/ej2-react-buttons';
export class TransactionTemplate extends React.Component {
    constructor(props) {
        super(props);
        this.state = Object.assign({}, props);
        this.qryBldrObj = getComponent(document.getElementById('querybuilder'), 'query-builder');
    }
    transactionChange(event) {
        const args = this.state;
        let elem = document.getElementById(args.ruleID).querySelector('.e-rule-value');
        this.qryBldrObj.notifyChange(event.checked === true ? 'Expense' : 'Income', elem, 'value');
    }
    render() {
        const args = this.state;
        return (<div>
                <CheckBoxComponent label="Is Expense" checked={args.rule.value} change={this.transactionChange.bind(this)}/>     
			</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.

Source
Preview
app.tsx
template.tsx
index.html
datasource.ts
app.jsx
template.jsx
Copied to clipboard
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';

class App extends React.Component<{}, {}> {
public qryBldrObj: QueryBuilderComponent;
public elem: HTMLElement;

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

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

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

public render() {
    return (
        <QueryBuilderComponent dataSource={employeeData} width='100%' rule={this.importRules} ref={(scope) => { this.qryBldrObj = scope as QueryBuilderComponent; }} actionBegin={this.actionBegin.bind(this)} 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={this.ageTemplate}/>
                <ColumnDirective field="City" label="City" type="string"/>
                <ColumnDirective field="Country" label="Country" type="string"/>
            </ColumnsDirective>
        </QueryBuilderComponent>
    );
}
}

ReactDom.render(<App />,document.getElementById('querybuilder-component'));
Copied to clipboard
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 class AgeTemplate extends React.Component<{}, {}> {
    public qryBldrObj: QueryBuilderComponent;
    public sliderObj: SliderComponent;
    public rangeTicks: object = { placement: 'Before', largeStep: 5, showSmallTicks: true };
    constructor(props: object) {
        super(props);
        this.state = Object.assign({}, props);
        this.qryBldrObj = getComponent(document.getElementById('querybuilder'), 'query-builder') as QueryBuilder;
    }

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

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

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

    public 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';
      }
    }

    public 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 = this.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'));
      });
    }

    public render() {
      const args: ActionEventArgs = this.state;
        return (
          <div className="e-rule e-rule-template">
            <div className="e-rule-filter e-custom-filter">
              <DropDownListComponent change={this.fieldChange.bind(this)} fields={args.fields} dataSource={args.columns} value={args.rule.field}/>
            </div>
			<div>
				<div className="e-slider-value">
					<SliderComponent ticks={this.rangeTicks} ref={(scope) => { this.sliderObj = scope as SliderComponent; }} id={args.ruleID + '_valuekey0'} change={this.valueChange.bind(this)} created={this.sliderCreated.bind(this)} value={args.rule.value} min={30} max={50} />
				</div>
				<div className="e-rule-btn">
					<button id={args.ruleID + '_option'} onClick={this.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>
        );
    }
}
Copied to clipboard
<!DOCTYPE html>
<html lang="en">

<head>
    <title>Syncfusion React Query Builder</title>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta name="description" content="Essential JS 2 for React Components" />
    <meta name="author" content="Syncfusion" />
    <link href="//cdn.syncfusion.com/ej2/ej2-base/styles/material.css" rel="stylesheet" />
    <link href="//cdn.syncfusion.com/ej2/ej2-buttons/styles/material.css" rel="stylesheet" />
    <link href="//cdn.syncfusion.com/ej2/ej2-splitbuttons/styles/material.css" rel="stylesheet" />
    <link href="//cdn.syncfusion.com/ej2/ej2-dropdowns/styles/material.css" rel="stylesheet" />
    <link href="//cdn.syncfusion.com/ej2/ej2-inputs/styles/material.css" rel="stylesheet" />
    <link href="//cdn.syncfusion.com/ej2/ej2-calendars/styles/material.css" rel="stylesheet" />
    <link href="//cdn.syncfusion.com/ej2/ej2-popups/styles/material.css" rel="stylesheet" />
    <link href="//cdn.syncfusion.com/ej2/ej2-querybuilder/styles/material.css" rel="stylesheet" />
	<link href="index.css" rel="stylesheet" />
    <script src="https://cdnjs.cloudflare.com/ajax/libs/systemjs/0.19.38/system.js"></script>
    <script src="systemjs.config.js"></script>
</head>

<body>
        <div id='querybuilder-component'>
            <div id='loader'>Loading....</div>
        </div>
</body>

</html>
Copied to clipboard
/**
 * QueryBuilder datasource
 */
export let employeeData: Array<{[key: string]: any}> = [
	{
		'Address': '507 - 20th Ave. E.\r\nApt. 2A',
		'Age': 30,
		'City': 'Seattle',
		'Country': 'USA',
		'EmployeeID': 1,
		'FirstName': 'Nancy',
		'HireDate': '22/07/2001',
		'LastName': 'Davolio',
		'PostalCode': '98122',
		'Region': 'WA',
		'Title': 'Sales Representative',
		'TitleOfCourtesy': 'Ms.'
	},
	{
		'Address': '908 W. Capital Way',
		'Age': 31,
		'City': 'Tacoma',
		'Country': 'USA',
		'EmployeeID': 2,
		'FirstName': 'Andrew',
		'HireDate': '21/04/2003',
		'LastName': 'Fuller',
		'PostalCode': '98401',
		'Region': 'WA',
		'Title': 'Vice President',
		'TitleOfCourtesy': 'Dr.'
	},
	{
		'Address': '722 Moss Bay Blvd.',
		'Age': 32,
		'City': 'Kirkland',
		'Country': 'USA',
		'EmployeeID': 3,
		'FirstName': 'Janet',
		'HireDate': '22/07/2001',
		'LastName': 'Leverling',
		'PostalCode': '98033',
		'Region': 'WA',
		'Title': 'Sales Representative',
		'TitleOfCourtesy': 'Ms.'
	},
	{
		'Address': '4110 Old Redmond Rd.',
		'Age': 33,
		'City': 'Redmond',
		'Country': 'USA',
		'EmployeeID': 4,
		'FirstName': 'Margaret',
		'HireDate': '22/07/2004',
		'LastName': 'Peacock',
		'PostalCode': '98052',
		'Region': 'WA',
		'Title': 'Sales Representative',
		'TitleOfCourtesy': 'Mrs.'
	},
	{
		'Address': '14 Garrett Hill',
		'Age': 34,
		'City': 'London',
		'Country': 'UK',
		'EmployeeID': 5,
		'FirstName': 'Steven',
		'HireDate': '02/04/2001',
		'LastName': 'Buchanan',
		'PostalCode': 'SW1 8JR',
		'Region': null,
		'Title': 'Sales Manager',
		'TitleOfCourtesy': 'Mr.'
	},
	{
		'Address': 'Coventry House\r\nMiner Rd.',
		'Age': 35,
		'City': 'London',
		'Country': 'UK',
		'EmployeeID': 6,
		'FirstName': 'Michael',
		'HireDate': '22/01/2003',
		'LastName': 'Suyama',
		'PostalCode': 'EC2 7JR',
		'Region': null,
		'Title': 'Sales Representative',
		'TitleOfCourtesy': 'Mr.'
	},
	{
		'Address': 'Edgeham Hollow\r\nWinchester Way',
		'Age': 36,
		'City': 'London',
		'Country': 'UK',
		'EmployeeID': 7,
		'FirstName': 'Robert',
		'HireDate': '22/07/2001',
		'LastName': 'King',
		'PostalCode': 'RG1 9SP',
		'Region': null,
		'Title': 'Sales Representative',
		'TitleOfCourtesy': 'Mr.'
	},
	{
		'Address': '4726 - 11th Ave. N.E.',
		'Age': 37,
		'City': 'Seattle',
		'Country': 'USA',
		'EmployeeID': 8,
		'FirstName': 'Laura',
		'HireDate': '22/07/2001',
		'LastName': 'Callahan',
		'PostalCode': '98105',
		'Region': 'WA',
		'Title': 'Inside Sales Coordinator',
		'TitleOfCourtesy': 'Ms.'
	},
	{
		'Address': '7 Houndstooth Rd.',
		'Age': 38,
		'City': 'London',
		'Country': 'UK',
		'EmployeeID': 9,
		'FirstName': 'Anne',
		'HireDate': '22/07/2001',
		'LastName': 'Dodsworth',
		'PostalCode': 'WG2 7LT',
		'Region': null,
		'Title': 'Sales Representative',
		'TitleOfCourtesy': 'Ms.'
	}
];
export let expenseData: Array<{[key: string]: any}>  = [
	{
		'Amount': '7',
		'Category': 'Food',
		'Description': 'Boiled peanuts',
		'FormattedDate': '06/01/2017 09:12 AM',
		'MonthFull': 'June, 2017',
		'MonthShort': 'Jun',
		'PaymentMode': 'Credit Card',
		'TransactionType': 'Expense',
		'UniqueId': 'T100001'
	},
	{
		'Amount': '8',
		'Category': 'Food',
		'Description': 'Peanuts in Coke',
		'FormattedDate': '06/04/2017 02:43 PM',
		'MonthFull': 'June, 2017',
		'MonthShort': 'Jun',
		'PaymentMode': 'Cash',
		'TransactionType': 'Expense',
		'UniqueId': 'T100024'
	},
	{
		'Amount': '11',
		'Category': 'Food',
		'Description': 'Palmetto Cheese, Mint julep',
		'FormattedDate': '06/04/2017 08:35 PM',
		'MonthFull': 'June, 2017',
		'MonthShort': 'Jun',
		'PaymentMode': 'Cash',
		'TransactionType': 'Expense',
		'UniqueId': 'T100025'
	},
	{
		'Amount': '9',
		'Category': 'Transportation',
		'Description': 'Cars and trucks, used',
		'FormattedDate': '06/04/2017 10:25 AM',
		'MonthFull': 'June, 2017',
		'MonthShort': 'Jun',
		'PaymentMode': 'Debit Card',
		'TransactionType': 'Expense',
		'UniqueId': 'T100026'
	},
	{
		'Amount': '8',
		'Category': 'Transportation',
		'Description': 'Public and other transportation',
		'FormattedDate': '06/04/2017 03:55 PM',
		'MonthFull': 'June, 2017',
		'MonthShort': 'Jun',
		'PaymentMode': 'Debit Card',
		'TransactionType': 'Expense',
		'UniqueId': 'T100027'
	},
	{
		'Amount': '160',
		'Category': 'Shopping',
		'Description': 'Household things & Utilities',
		'FormattedDate': '06/04/2017 10:22 AM',
		'MonthFull': 'June, 2017',
		'MonthShort': 'Jun',
		'PaymentMode': 'Cash',
		'TransactionType': 'Expense',
		'UniqueId': 'T100028'
	},
	{
		'Amount': '110',
		'Category': 'Extra income',
		'Description': 'Income from Sale',
		'FormattedDate': '11/30/2017 02:42 PM',
		'MonthFull': 'November, 2017',
		'MonthShort': 'Nov',
		'PaymentMode': 'Cash',
		'TransactionType': 'Income',
		'UniqueId': 'T101284'
	}
];
export let hardwareData: Array<{[key: string]: any}>  = [
	{
		'AssignedTo': 'John Doe',
		'Category': 'Laptop',
		'DOP': '04/10/2018',
		'InvoiceNo': 'INV-2878',
		'Name': 'Lenovo Yoga',
		'Note': 'Remarks are noted',
		'SerialNo': 'CB27932009',
		'Status': 'Assigned',
		'TaskID': 1,
		'WEO': '05/01/2021'
	},
	{
		'AssignedTo': '',
		'Category': 'Others',
		'DOP': '02/12/2018',
		'InvoiceNo': 'INV-3456',
		'Name': 'Acer Aspire',
		'Note': 'Remarks are noted',
		'SerialNo': 'CB35728290',
		'Status': 'In-repair',
		'TaskID': 2,
		'WEO': '03/01/2023'
	},
	{
		'AssignedTo': '',
		'Category': 'Laptop',
		'DOP': '04/10/2018',
		'InvoiceNo': 'INV-2763',
		'Name': 'Apple MacBook',
		'Note': 'Remarks are noted',
		'SerialNo': 'CB35628728',
		'Status': 'In-repair',
		'TaskID': 3,
		'WEO': '04/03/2021'
	},
	{
		'AssignedTo': '',
		'Category': 'Laptop',
		'DOP': '03/09/2018',
		'InvoiceNo': 'INV-2980',
		'Name': 'Lenovo ThinkPad',
		'Note': 'Remarks are noted',
		'SerialNo': 'CB56209872',
		'Status': 'Pending',
		'TaskID': 4,
		'WEO': '05/12/2021'
	},
	{
		'AssignedTo': 'David Anto',
		'Category': 'Laptop',
		'DOP': '01/10/2018',
		'InvoiceNo': 'INV-3782',
		'Name': 'Dell Inspiron',
		'Note': 'Remarks are noted',
		'SerialNo': 'CB56289036',
		'Status': 'Assigned',
		'TaskID': 5,
		'WEO': '04/01/2021'
	},
	{
		'AssignedTo': 'Mary Saveley',
		'Category': 'Laptop',
		'DOP': '04/10/2018',
		'InvoiceNo': 'INV-2712',
		'Name': 'HP Pavilion',
		'Note': 'Remarks are noted',
		'SerialNo': 'CB56289305',
		'Status': 'Assigned',
		'TaskID': 6,
		'WEO': '05/01/2021'
	},
	{
		'AssignedTo': '',
		'Category': 'Laptop',
		'DOP': '06/16/2018',
		'InvoiceNo': 'INV-0984',
		'Name': 'Asus ZenBook',
		'Note': 'Remarks are noted',
		'SerialNo': 'CB25637891',
		'Status': 'Pending',
		'TaskID': 7,
		'WEO': '09/01/2021'
	},
	{
		'AssignedTo': '',
		'Category': 'Laptop',
		'DOP': '02/19/2018',
		'InvoiceNo': 'INV-2561',
		'Name': 'HP EliteBook',
		'Note': 'Remarks are noted',
		'SerialNo': 'CB27819726',
		'Status': 'Ordered',
		'TaskID': 8,
		'WEO': '05/21/2021'
	},
	{
		'AssignedTo': '',
		'Category': 'Laptop',
		'DOP': '02/12/2018',
		'InvoiceNo': 'INV-8970',
		'Name': 'Apple MacBook Air',
		'Note': 'Remarks are noted',
		'SerialNo': 'CB05262880',
		'Status': 'Pending',
		'TaskID': 9,
		'WEO': '03/01/2023'
	},
	{
		'AssignedTo': '',
		'Category': 'Tablet',
		'DOP': '04/10/2018',
		'InvoiceNo': 'INV-4555',
		'Name': 'Apple iPad Air',
		'Note': 'Remarks are noted',
		'SerialNo': 'CB45262777',
		'Status': 'Pending',
		'TaskID': 10,
		'WEO': '05/01/2021'
	}
];
Copied to clipboard
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';
class App extends React.Component {
    constructor() {
        super(...arguments);
        this.importRules = {
            'condition': 'or',
            'rules': [{
                    'field': 'Age',
                    'label': 'Age',
                    'operator': 'greaterthanorequal',
                    'type': 'number',
                    'value': 30
                }]
        };
    }
    ageTemplate(props) {
        return (<AgeTemplate {...props}/>);
    }
    actionBegin(args) {
        this.ruleID = args.ruleID;
        args.rule.operator = 'greaterthanorequal';
        if (args.requestType === 'template-initialize') {
            if (args.rule.value === '') {
                args.rule.value = 30;
            }
        }
    }
    render() {
        return (<QueryBuilderComponent dataSource={employeeData} width='100%' rule={this.importRules} ref={(scope) => { this.qryBldrObj = scope; }} actionBegin={this.actionBegin.bind(this)} 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={this.ageTemplate}/>
                <ColumnDirective field="City" label="City" type="string"/>
                <ColumnDirective field="Country" label="Country" type="string"/>
            </ColumnsDirective>
        </QueryBuilderComponent>);
    }
}
ReactDom.render(<App />, document.getElementById('querybuilder-component'));
Copied to clipboard
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 class AgeTemplate extends React.Component {
    constructor(props) {
        super(props);
        this.rangeTicks = { placement: 'Before', largeStep: 5, showSmallTicks: true };
        this.state = Object.assign({}, props);
        this.qryBldrObj = getComponent(document.getElementById('querybuilder'), 'query-builder');
    }
    fieldChange(args) {
        this.qryBldrObj.notifyChange(args.value, args.element, 'field');
    }
    valueChange(args) {
        let elem = this.sliderObj.element;
        this.qryBldrObj.notifyChange(args.value, elem, 'value');
        this.refreshTable(this.qryBldrObj.getRule(elem), elem.id.split('_valuekey0')[0]);
    }
    sliderCreated() {
        let elem = this.sliderObj.element;
        this.refreshTable(this.qryBldrObj.getRule(elem), elem.id.split('_valuekey0')[0]);
    }
    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';
        }
    }
    refreshTable(rule, ruleID) {
        let template = '<tr><td>${EmployeeID}</td><td>${FirstName}</td><td>${Age}</td></tr>';
        let compiledFunction = compile(template);
        let predicate = this.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'));
        });
    }
    render() {
        const args = this.state;
        return (<div className="e-rule e-rule-template">
            <div className="e-rule-filter e-custom-filter">
              <DropDownListComponent change={this.fieldChange.bind(this)} fields={args.fields} dataSource={args.columns} value={args.rule.field}/>
            </div>
			<div>
				<div className="e-slider-value">
					<SliderComponent ticks={this.rangeTicks} ref={(scope) => { this.sliderObj = scope; }} id={args.ruleID + '_valuekey0'} change={this.valueChange.bind(this)} created={this.sliderCreated.bind(this)} value={args.rule.value} min={30} max={50}/>
				</div>
				<div className="e-rule-btn">
					<button id={args.ruleID + '_option'} onClick={this.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>);
    }
}