Templates in EJ2 TypeScript Query builder control

27 Apr 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 in querybuilder, you can create the user interface using x-template 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 { QueryBuilder, RuleModel, ColumnsModel, ActionEventArgs} from  '@syncfusion/ej2-querybuilder'
import { closest } from '@syncfusion/ej2-base';
import { DropDownButton, ItemModel, MenuEventArgs } from '@syncfusion/ej2-splitbuttons';
import { DropDownList } from '@syncfusion/ej2-dropdowns';
import { CheckBox } from '@syncfusion/ej2-buttons';

let filter: ColumnsModel [] = [
    { field: 'EmployeeID', label: 'EmployeeID', type: 'number'},
    { field: 'FirstName', label: 'FirstName', type: 'string'},
    { field: 'LastName', label: 'LastName', type: 'string'},
    { field: 'Age', label: 'Age', type: 'number'},
    { field: 'City', label: 'City', type: 'string'},
    { field: 'Country', label: 'Country', type: 'string'},
];

let importRules: RuleModel = {
    'condition': 'and', 'not': true,
    'rules': [{
        'label': 'Age',
        'field': 'Age',
        'type': 'number',
        'operator': 'equal',
        'value': 34
    },
    {
        'label': 'LastName',
        'field': 'LastName',
        'type': 'string',
        'operator': 'equal',
        'value': 'vinit'
    },
    {
    'condition': 'or',
    'rules': [{
        'label': 'Age',
        'field': 'Age',
        'type': 'number',
        'operator': 'equal',
        'value': 34
    }]
}]
};

let queryBldrObj: QueryBuilder = new QueryBuilder({
    columns: filter,
    width: '100%',
    rule: importRules,
    headerTemplate: '#headerTemplate',
    actionBegin: actionBegin,
    enableNotCondition: true
});
queryBldrObj.appendTo('#querybuilder');

    function actionBegin(args: ActionEventArgs): void {
        if (args.requestType === 'header-template-create') {
            let checkBoxObj: CheckBox = new CheckBox({
                label: 'NOT',
                checked: args.notCondition,
                change: function(e:any){
                    queryBldrObj.notifyChange(e.checked,e.event.target, 'not')
                }
             });
            checkBoxObj.appendTo('#' + args.ruleID + '_notoption');
            let ds: { [key: string]: Object }[] = [{'key': 'AND', 'value': 'and'},{'key': 'OR', 'value': 'or'}];
            let btnObj: DropDownList= new DropDownList({
                dataSource: ds,
                fields: { text: 'key', value: 'value' },
                value: args.condition,
                cssClass: 'e-custom-group-btn e-active-toggle',
                change: (e: any) => {
                    queryBldrObj.notifyChange(e.value, e.element, 'condition');
                }
            });
            btnObj.appendTo('#' + args.ruleID + '_cndtnbtn');
            let ddbitems: ItemModel[] = [
                { text: 'AddGroup', iconCss: 'e-icons e-add-icon e-addgroup' },
                { text: 'AddCondition', iconCss: 'e-icons e-add-icon e-addrule' }
            ];
            let addbtn: DropDownButton = new DropDownButton({
                items: ddbitems,
                cssClass: 'e-round e-small e-caret-hide e-addrulegroup',
                iconCss: 'e-icons e-add-icon',
                select: function(event: MenuEventArgs) {
                    let addbtn: Element = closest(event.element,'.e-dropdown-popup');  let ddb: string[]= addbtn.id.split('_');
                    if (event.item.text === 'AddGroup') {
                        queryBldrObj.addGroups([{condition: 'and', 'rules': [{}], not: false}], ddb[1]);
                    } else if (event.item.text === 'AddCondition') {
                        queryBldrObj.addRules([{}], ddb[1]);
                    }
                }
            });
            addbtn.appendTo('#' + args.ruleID + '_addbtn');
            let deleteGroup: Element =  document.getElementById(args.ruleID).querySelector('.e-delete-btn');
            if (deleteGroup) {
                (deleteGroup as HTMLElement).onclick = function (e:any) {
                    queryBldrObj.deleteGroup(closest(e.target.offsetParent, '.e-group-container'));
                }
            }
        }
    }
<!DOCTYPE html>
<html lang="en">

<head>
    <title>EJ2 Query Builder</title>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta name="description" content="Typescript UI Controls" />
    <meta name="author" content="Syncfusion" />
    <link href="https://cdn.syncfusion.com/ej2/25.1.35/ej2-base/styles/material.css" rel="stylesheet" />
    <link href="https://cdn.syncfusion.com/ej2/25.1.35/ej2-buttons/styles/material.css" rel="stylesheet" />
    <link href="https://cdn.syncfusion.com/ej2/25.1.35/ej2-splitbuttons/styles/material.css" rel="stylesheet" />
    <link href="https://cdn.syncfusion.com/ej2/25.1.35/ej2-dropdowns/styles/material.css" rel="stylesheet" />
    <link href="https://cdn.syncfusion.com/ej2/25.1.35/ej2-inputs/styles/material.css" rel="stylesheet" />
    <link href="https://cdn.syncfusion.com/ej2/25.1.35/ej2-calendars/styles/material.css" rel="stylesheet" />
    <link href="https://cdn.syncfusion.com/ej2/25.1.35/ej2-popups/styles/material.css" rel="stylesheet" />
    <link href="https://cdn.syncfusion.com/ej2/25.1.35/ej2-querybuilder/styles/material.css" rel="stylesheet" />
    <link href="styles.css" rel="stylesheet" />
    <script src="https://cdnjs.cloudflare.com/ajax/libs/systemjs/0.19.38/system.js"></script>
    <script src="systemjs.config.js"></script>
    
<script src="https://cdn.syncfusion.com/ej2/syncfusion-helper.js" type ="text/javascript"></script>
</head>

<body>
    <div id='loader'>LOADING....</div>
    <div id='container'>
        <div id='querybuilder'></div>
    </div>
    <script id="headerTemplate" type="text/x-template">
        <div class = 'e-groupheader'>
            ${if(notCondition !== undefined)}
                <button class='e-cb-wrapper'>
                    <input type="checkbox" class= "e-not" id='${ruleID}_notoption' checked='${notCondition}'>
                </button>
            ${/if}
            <input type="text" class= "e-custom-group-btn"  id='${ruleID}_cndtnbtn'>
            <button id = '${ruleID}_addbtn' class = 'e-add-btn'></button>
            ${if(ruleID !== 'querybuilder_group0')}
                <button  id= 'dltbtn' class = "e-btn e-delete-btn e-lib e-small e-round e-icon-btn">
                    <span class = 'e-btn-icon e-icons e-delete-icon'></span>
                </button>
            ${/if}
        </div>
    </script>
    <style type="text/css">
    .e-query-builder .e-add-btn {
        margin-left: 10px;
        margin-right: 10px;
    }
    .e-query-builder .cndtnbtn.e-control.e-dropdownlist.e-lib.e-input {
        padding-left: 10px;
    }
    .e-query-builder span.e-custom-group-btn {
        max-width: 100px;
        border-radius: 5px  !important;
        border-width: 1px  !important; 
    }
    .e-query-builder .e-custom-group-btn.e-input-focus::before, .e-custom-group-btn.e-input-focus::after {
        background: transparent !important;
    }
    .e-query-builder .e-group-header .e-addrulegroup, .e-group-header .e-delete-btn {
        border: 1px solid grey !important;
    }
    .e-query-builder .e-group-header .e-addrulegroup:hover, .e-group-header .e-delete-btn:hover {
        border: 1px solid grey !important;
    }
    .e-query-builder .e-toggle{
        background: #317ab9;
        border-color: #317ab9;
        color: #fff;
    }
    .e-query-builder .e-cb-wrapper {
        margin-right: 5px;
        height: 32px;
        border-radius: 5px;
        border: 1px solid gray;
        background-color: white;
    }
    .e-query-builder .e-custom-group-btn{
        padding-left: 10px;
        height: 32px;
    }
    </style>
</body>
</html>

Column Template

Column 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 { QueryBuilder, ColumnsModel, RuleModel } from '@syncfusion/ej2-querybuilder';
import { getComponent } from '@syncfusion/ej2-base';
import { TextBox } from '@syncfusion/ej2-inputs';
import { DropDownList, MultiSelect, CheckBoxSelection } from '@syncfusion/ej2-dropdowns';

let expenseData: Object[]  = [{
    'Category': 'Food',
    'PaymentMode': 'Credit Card',
    'TransactionType': 'Expense',
    'Description': 'Boiled peanuts',
    'Amount': '7',
    'Date': '06/01/2017'
  }, {

    'Category': 'Food',
    'PaymentMode': 'Cash',
    'TransactionType': 'Expense',
    'Description': 'Peanuts in Coke',
    'Amount': '8',
    'Date': '06/04/2017'
  }, {
    'Category': 'Food',
    'PaymentMode': 'Cash',
    'TransactionType': 'Expense',
    'Description': 'Palmetto Cheese, Mint julep',
    'Amount': '11',
    'Date': '06/04/2017'
  }];

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

    let importRules: RuleModel = {
        'condition': 'and',
        'rules': [{
                'label': 'Payment Mode',
                'field': 'PaymentMode',
                'type': 'string',
                'operator': 'equal',
                'value': 'Cash'
            }
        ]
    };
    let qryBldrObj: QueryBuilder = new QueryBuilder({
        dataSource: expenseData,
        columns: columnData,
        width: '70%',
        rule: importRules
    });
    qryBldrObj.appendTo('#querybuilder');
<!DOCTYPE html>
<html lang="en">

<head>
    <title>EJ2 Query Builder</title>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta name="description" content="Typescript UI Controls" />
    <meta name="author" content="Syncfusion" />
    <link href="https://cdn.syncfusion.com/ej2/25.1.35/ej2-base/styles/material.css" rel="stylesheet" />
    <link href="https://cdn.syncfusion.com/ej2/25.1.35/ej2-buttons/styles/material.css" rel="stylesheet" />
    <link href="https://cdn.syncfusion.com/ej2/25.1.35/ej2-splitbuttons/styles/material.css" rel="stylesheet" />
    <link href="https://cdn.syncfusion.com/ej2/25.1.35/ej2-dropdowns/styles/material.css" rel="stylesheet" />
    <link href="https://cdn.syncfusion.com/ej2/25.1.35/ej2-inputs/styles/material.css" rel="stylesheet" />
    <link href="https://cdn.syncfusion.com/ej2/25.1.35/ej2-calendars/styles/material.css" rel="stylesheet" />
    <link href="https://cdn.syncfusion.com/ej2/25.1.35/ej2-popups/styles/material.css" rel="stylesheet" />
    <link href="https://cdn.syncfusion.com/ej2/25.1.35/ej2-querybuilder/styles/material.css" rel="stylesheet" />
    <link href="styles.css" rel="stylesheet" />
    <script src="https://cdnjs.cloudflare.com/ajax/libs/systemjs/0.19.38/system.js"></script>
    <script src="systemjs.config.js"></script>
    
<script src="https://cdn.syncfusion.com/ej2/syncfusion-helper.js" type ="text/javascript"></script>
</head>

<body>
    <div id='loader'>LOADING....</div>
    <div id='container'>
        <div id='querybuilder'></div>
         <div id='property'> </div>
    </div>
</body>
</html>

Using Template

Template allows you to define your own input widgets for columns. To implement template in querybuilder, you can create the user interface using x-template and assign the values through actionBegin event.

import { QueryBuilder, RuleModel, ColumnsModel, ActionEventArgs} from '@syncfusion/ej2-querybuilder';
import { DropDownList } from '@syncfusion/ej2-dropdowns';
import { CheckBox } from '@syncfusion/ej2-buttons';

let filter: ColumnsModel [] = [
    { field:"Category" label:"Category" type:"string"},
    { field: 'PaymentMode', label: 'PaymentMode', type: 'string', operators: customOperators , template:"#paymentTemplate"},
    { field: 'TransactionType', label: 'TransactionType', type: 'string',  operators: customOperators, template:"#transactionTemplate"},
    { field: 'Description', label: 'Description', type: 'string' },
    { field: 'Date', label: 'Date', type: 'string'},
    { field: 'Amount', label: 'Amount', type: 'string'},
];

let customOperators: { [key: string]: Object }[] = [{value: 'equal', key: 'Equal'},
  {value: 'notequal', key: 'Not Equal'}];
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'
  }]
};

let valueObj: Slider;
let queryBldrObj: QueryBuilder = new QueryBuilder({
    columns: filter,
    rule: importRules,
    width: '100%',
    actionBegin: actionBegin
});
queryBldrObj.appendTo('#querybuilder');


function actionBegin(args: ActionEventArgs): void {
    let ruleID: string = args.ruleID
    if (args.requestType === 'value-template-create') {
        let checkBoxObj: CheckBox = new CheckBox({
            label: 'Is Expense',
            checked: args.rule.value === "Expense" ? true: false,
            change: function(e:any){
                let elem: HTMLElement = document.getElementById(ruleID).querySelector('.e-rule-value');qryBldrObj.notifyChange(e.checked === true ? 'Expense' : 'Income', elem, 'value');
            }
        });
        checkBoxObj.appendTo('#' + args.ruleID + '_checkbox');
        let ds: string[] = ['Cash', 'Debit Card', 'Credit Card', 'Net Banking'];
        let btnObj: DropDownList= new DropDownList({
                dataSource: ds,
                fields: { text: 'key', value: 'value' },
                value: args.rule.value,
                change: (e: any) => {
                 let elem: HTMLElement = document.getElementById(ruleID).querySelector('.e-rule-value');qryBldrObj.notifyChange(e.value as string, elem, 'value');
                }
        });
        btnObj.appendTo('#' + args.ruleID + '_paymentlist');
    }
}
<!DOCTYPE html>
<html lang="en">

<head>
    <title>EJ2 Query Builder</title>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta name="description" content="Typescript UI Controls" />
    <meta name="author" content="Syncfusion" />
    <link href="https://cdn.syncfusion.com/ej2/25.1.35/ej2-base/styles/material.css" rel="stylesheet" />
    <link href="https://cdn.syncfusion.com/ej2/25.1.35/ej2-buttons/styles/material.css" rel="stylesheet" />
    <link href="https://cdn.syncfusion.com/ej2/25.1.35/ej2-splitbuttons/styles/material.css" rel="stylesheet" />
    <link href="https://cdn.syncfusion.com/ej2/25.1.35/ej2-dropdowns/styles/material.css" rel="stylesheet" />
    <link href="https://cdn.syncfusion.com/ej2/25.1.35/ej2-inputs/styles/material.css" rel="stylesheet" />
    <link href="https://cdn.syncfusion.com/ej2/25.1.35/ej2-calendars/styles/material.css" rel="stylesheet" />
    <link href="https://cdn.syncfusion.com/ej2/25.1.35/ej2-popups/styles/material.css" rel="stylesheet" />
    <link href="https://cdn.syncfusion.com/ej2/25.1.35/ej2-querybuilder/styles/material.css" rel="stylesheet" />
    <link href="styles.css" rel="stylesheet" />
    <script src="https://cdnjs.cloudflare.com/ajax/libs/systemjs/0.19.38/system.js"></script>
    <script src="systemjs.config.js"></script>
    
<script src="https://cdn.syncfusion.com/ej2/syncfusion-helper.js" type ="text/javascript"></script>
</head>

<body>
    <div id='loader'>LOADING....</div>
    <div id='container'>
        <div id='querybuilder'></div>
    </div>
    <script id="paymentTemplate" type="text/x-template">
        <input type="text" class= "e-payment-list"  id='${ruleID}_paymentlist'>
    </script>
    <script id="transactionTemplate" type="text/x-template">
        <input type="checkbox" class= "e-checkbox"  id='${ruleID}_checkbox'>
    </script>
    
	<style type="text/css">
		
	</style>
</body>
</html>

Rule Template

Rule Template allows to define your own user interface for columns. To implement ruleTemplate, you can create the user interface using x-template and assign the values through actionBegin event.

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

import { QueryBuilder, RuleModel, ColumnsModel, ActionEventArgs} from '@syncfusion/ej2-querybuilder';
import { DropDownList } from '@syncfusion/ej2-dropdowns';
import { Slider } from '@syncfusion/ej2-inputs';
import { employeeData } from './datasource.ts';
import { DataManager, Query } from '@syncfusion/ej2-data';
import { compile } from '@syncfusion/ej2-base';

let filter: ColumnsModel [] = [
    { field: 'EmployeeID', label: 'EmployeeID', type: 'number'},
    { field: 'FirstName', label: 'FirstName', type: 'string'},
    { field: 'LastName', label: 'LastName', type: 'string'},
    { field: 'Age', label: 'Age', type: 'number', ruleTemplate: '#ageTemplate'},
    { field: 'City', label: 'City', type: 'string'},
    { field: 'Country', label: 'Country', type: 'string'},
];

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

let fieldObj: DropDownList;
let valueObj: Slider;
let ruleID: string;

let queryBldrObj: QueryBuilder = new QueryBuilder({
    columns: filter,
    dataSource: employeeData,
    rule: importRules,
    width: '100%',
    actionBegin: actionBegin
});
queryBldrObj.appendTo('#querybuilder');

function actionBegin(args: ActionEventArgs): void {
    ruleID = args.ruleID;
    if (args.requestType === 'template-create') {
        args.rule.operator = 'greaterthanorequal';
        fieldObj = new DropDownList({
            dataSource: this.columns, // tslint:disable-line
            fields: args.fields,
            value: args.rule.field,
            change: (e: any) => {
                queryBldrObj.notifyChange(e.value, e.element, 'field');
            }
        });
        if (args.rule.value === '') {
            args.rule.value = 30;
        }
        valueObj = new Slider({
            value: args.rule.value as number,
            min: 30,
            max: 50,
            ticks: { placement: 'Before', largeStep: 5, smallStep: 1, showSmallTicks: true },
            change: (e: any) => {
                let elem: HTMLElement = valueObj.element;
                queryBldrObj.notifyChange(e.value, elem, 'value');
                refreshTable(queryBldrObj.getRule(elem), elem.id.split('_valuekey0')[0]);
            },
            created: () => {
                let elem: HTMLElement = valueObj.element;
                refreshTable(queryBldrObj.getRule(elem), elem.id.split('_valuekey0')[0]);
            }
        });
        fieldObj.appendTo('#' + args.ruleID + '_filterkey');
        valueObj.appendTo('#' + args.ruleID + '_valuekey0');
    }
}

function refreshTable(rule: RuleModel, ruleID: string) {
    let template: string = '<tr><td>${EmployeeID}</td><td>${FirstName}</td><td>${Age}</td></tr>';
    let compiledFunction: Function = compile(template);
    let predicate = queryBldrObj.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 = (<HTMLElement>document.querySelector('#' + ruleID + '_section #datatable'));
    if (result.length) {
        table.style.display = 'block';
    } else {
        table.style.display = 'none';
    }
    table.querySelector('tbody').innerHTML = '';
    result.forEach((data: Object) => {
        table.querySelector('tbody').appendChild(compiledFunction(data)[0].querySelector('tr'));
    });
}
<!DOCTYPE html>
<html lang="en">

<head>
    <title>EJ2 Query Builder</title>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta name="description" content="Typescript UI Controls" />
    <meta name="author" content="Syncfusion" />
    <link href="https://cdn.syncfusion.com/ej2/25.1.35/ej2-base/styles/material.css" rel="stylesheet" />
    <link href="https://cdn.syncfusion.com/ej2/25.1.35/ej2-buttons/styles/material.css" rel="stylesheet" />
    <link href="https://cdn.syncfusion.com/ej2/25.1.35/ej2-splitbuttons/styles/material.css" rel="stylesheet" />
    <link href="https://cdn.syncfusion.com/ej2/25.1.35/ej2-dropdowns/styles/material.css" rel="stylesheet" />
    <link href="https://cdn.syncfusion.com/ej2/25.1.35/ej2-inputs/styles/material.css" rel="stylesheet" />
    <link href="https://cdn.syncfusion.com/ej2/25.1.35/ej2-calendars/styles/material.css" rel="stylesheet" />
    <link href="https://cdn.syncfusion.com/ej2/25.1.35/ej2-popups/styles/material.css" rel="stylesheet" />
    <link href="https://cdn.syncfusion.com/ej2/25.1.35/ej2-querybuilder/styles/material.css" rel="stylesheet" />
    <link href="styles.css" rel="stylesheet" />
    <script src="https://cdnjs.cloudflare.com/ajax/libs/systemjs/0.19.38/system.js"></script>
    <script src="systemjs.config.js"></script>
    
<script src="https://cdn.syncfusion.com/ej2/syncfusion-helper.js" type ="text/javascript"></script>
</head>

<body>
    <div id='loader'>LOADING....</div>
    <div id='container'>
        <div id='querybuilder'></div>
    </div>
	<script id="ageTemplate" type="text/x-template">
        <div class="e-rule e-rule-template">
            <div class="e-rule-filter e-custom-filter">
                <input id = ${ruleID}_filterkey class='e-filter-input'>
            </div>
			<div>
				<div class="e-value e-rule-value e-slider-value">
					<div id = ${ruleID}_valuekey0 class="ticks_slider"></div>
				</div>
				<div class="e-rule-btn">
					<button id=${ruleID}_option onclick="myFunction(${ruleID})" class="e-primary e-btn e-small">
						View Details
					</button>
					<button class="e-removerule e-rule-delete e-css e-btn e-small e-round">
						<span class="e-btn-icon e-icons e-delete-icon"/>
					</button>
				</div>
			</div>
            <div id=${ruleID}_section class="e-rule-value-group e-hide">
                <div>
                    <table id='datatable' class='e-table e-rule-table' style='display:none'>
                        <thead>
                            <tr><th>EmployeeID</th><th>FirstName</th><th>Age</th></tr>
                        </thead>
                        <tbody>
                        </tbody>
                    </table>     
                </div>
            </div>
        </div>
    </script>

    <script type="text/javascript">
        function myFunction(ruleElem) {
            var element = document.getElementById(ruleElem.id + '_section');
            if (element.className.indexOf('e-hide') > -1) {
                element.className = element.className.replace('e-hide', '');
                document.getElementById(ruleElem.id + '_option').textContent = 'Hide Details';
            } else {
                element.className += ' e-hide';
                document.getElementById(ruleElem.id + '_option').textContent = 'View Details';
            }
        }
    </script>
	<style type="text/css">
		.e-query-builder .e-custom-filter {
			width: 40% !important;
		}
		.e-query-builder .e-slider-value {
			width: 40% !important;
			padding: 12px 0 12px 0 !important;
			display: inline-block;
		}
		.e-query-builder .e-slider-container.e-horizontal {
			padding: 0 0 0 18px;
			height: 0;
		}
		.e-query-builder .e-slider-container.e-horizontal .e-slider {
			top: calc(50% - 10px);
		}
	</style>
</body>
</html>