Dependent elements within a query builder

Hi,
It is my intention to implement a one-level query builder (where the max groups is set to 0). The user can add as many conditions to the top-level group as they like. The query builder will be inside a form control and there will be other input elements for the user to provide input on.

My current page has a set of inputs that bind to a viewmodel using razor markup. Obviously this would have to be replaced by stringified json generated by the query builder, but this is not a problem.

I will provide snippets below. My current implementation is one set of inputs - I need these to be replicated dynamically so I would like to use querybuilder for it.
Two of these inputs are drop-down boxes and the second of these box's selection items is dependent on the selection in the first. Currently I use Jquery to populate this second box.
Is this behaviour achievable with querybuilder? The first drop-down selection list will be fixed, but the second will be dynamic as explained above. Snippets below. The elements I wish to include i the query builder have the class "group". The snippet is a simple form, other forms will have these "group" elements and some other elements for user input that will not be part of the query builder.

Many thanks
Kind regards
Will

View:

@using (Html.BeginForm("Edit", "ItemNotReturnable", FormMethod.Post))
{
@Html.AntiForgeryToken()

@*@await Html.PartialAsync("_CommonRulesInputs", Model)*@
<div class="group">
    @Html.Label("Test 1")
    @Html.DropDownListFor(m => Model.PropertyToCompareAgainst, Model.PropertiesToCompareAgainst, "Select Property",
                          new { @class = "form-control", id = "ddid1", style = "width:250px;max-width:250px;" })
</div>
<div class="group">
    @Html.Label("Test 1")
    @Html.DropDownListFor(m => Model.Comparison,
    Model.Comparisons,
         "Select Comparison",
         new { @class = "form-control", id = "ddid2", style = "width:250px;max-width:250px;" })
</div>
<div class="group">
    @Html.Label("Test 1")
    @Html.TextBoxFor(m => Model.Value)
</div>
<div class="group">
    @Html.Label("Test 1")
    @Html.EditorFor(m => Model.Priority,
                    new { htmlAttributes = new { type = "number", min = "1", max = "100", @class = "form-control", style = "width:100px;max-width:100px;" } })
</div>

@Html.HiddenFor(m => m.RuleId)
@Html.HiddenFor(m => m.RuleSetId)
<div>
    <input type="submit" value="Submit" />
</div>

}


<script>
    $("#ddid1").on("change", function(){
        showValue($(this).val());
    })

    function showValue(val)
    {
        $.getJSON('@Url.Action("GetComparisons", "ItemNotReturnable")' + "?value=" + val, function (result) {
            $("#ddid2").html(""); // makes select null before filling process
                var data = result.data;
                for (var i = 0; i < data.length; i++) {
                    $("#ddid2").append("<option>"+ data[i] +"</option>")
                }
        })
    }
</script>

Model:
 
public class CreateRuleModel
    {
        [Required]
        public string PropertyToCompareAgainst { get; set; }

        public IEnumerable<SelectListItem> PropertiesToCompareAgainst { get; set; }

        [Required]
        public string Comparison { get; set; }

        public IEnumerable<SelectListItem> Comparisons { get; set; }

        [Required]
        public string Value { get; set; }

        public InterfaceControlType ControlType { get; set; }

        public int? Priority { get; set; }

        public int RuleSetId { get; set; }

        public int RuleId { get; set; }
    }

GetComparisons controller action:

 [HttpGet]
        public IActionResult GetComparisons(string value)
        {
            var data = RulesControllerUtil.PopulateAvailablsComparisonsList(value, _classToUse);

            var datatoReturn = data.Select(x => x.Value);

            return Json(new { data = datatoReturn });
        }

1 Reply 1 reply marked as answer

MK Mohan Kumar Ramasamy Syncfusion Team December 9, 2020 06:55 AM UTC

Hi Will Chambers, 
 
We have checked your reported query. We can achieve your requirement using rule template. For this, we have triggered ‘actionBegin’ event before control rendering and assigned ‘ruleTemplate’ for all the columns. Please refer below code snippets. 
 
 
<div class="col-lg-12 control-section"> 
    <ejs-querybuilder id="querybuilder" width="73%" rule="ViewBag.rule" created="Created" separator="." ruleChange="updateRule" actionBegin="actionBegin"> 
        <e-querybuilder-columns> 
            <e-querybuilder-column field="EmployeeID" label="Employee ID" type="number"></e-querybuilder-column> 
            <e-querybuilder-column field="FirstName" label="First Name" type="string"></e-querybuilder-column> 
            <e-querybuilder-column field="LastName" label="Last Name" type="string"></e-querybuilder-column> 
            <e-querybuilder-column field="Address" label="Address" type="string" ruleTemplate="#QueryBuilderTemplate"></e-querybuilder-column> 
        </e-querybuilder-columns> 
    </ejs-querybuilder> 
</div> 
 
<div class="col-lg-4 property-section"> 
    <table id="property" title="Properties" class="querybuilder-property"> 
        <tr> 
            <td colspan="2"> 
                <textarea id='ruleContent' readonly=true> </textarea> 
            </td> 
        </tr> 
    </table> 
</div> 
 
<script id="QueryBuilderTemplate" 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'> 
                <input id = ${ruleID}_filterkey1 class='e-filter-input'> 
            </div> 
 
    <div class="e-rule-operator e-operator"> 
                <input id = ${ruleID}_operatorkey class='e-operator-input'> 
            </div> 
 
    <div class="e-rule-value e-value e-custom-value"> 
                <input id = ${ruleID}_valuekey0 class='e-value-input'> 
            </div> 
        <div class="e-rule-value-delete"> 
                <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> 
 
 
 
</script> 
 
<script> 
 
    var customOperator = [ 
        { value: 'equal', key: 'Equal' }, 
        { value: 'notequal', key: 'Not Equal' }, 
        { value: 'in', key: 'In' }, 
        { value: 'notin', key: 'Not In' } 
    ]; 
 
    var employeeData = [ 
        { 
            'EmployeeID': 1, 
            'LastName': 'Davolio', 
            'FirstName': 'Nancy', 
            'Address': { 
                'No': '1', 
                'StreetName': '17th Avenue', 
                'City': 'Seattle', 
                'Country': 'USA' 
            } 
        }, 
        { 
            'EmployeeID': 2, 
            'LastName': 'Fuller', 
            'FirstName': 'Andrew', 
            'Address': { 
                'No': '2', 
                'StreetName': '18th Avenue', 
                'City': 'Tacoma', 
                'Country': 'USA' 
            } 
        }, 
        { 
            'EmployeeID': 3, 
            'LastName': 'Leverling', 
            'FirstName': 'Janet', 
            'Address': { 
                'No': '1', 
                'StreetName': '19th Avenue', 
                'City': 'Kirkland', 
                'Country': 'USA' 
            } 
        }, 
        { 
            'EmployeeID': 4, 
            'LastName': 'Peacock', 
            'FirstName': 'Margaret', 
            'Address': { 
                'No': '1', 
                'StreetName': '17th Avenue', 
                'City': 'Redmond', 
                'Country': 'USA' 
            } 
        }, 
        { 
            'EmployeeID': 5, 
            'LastName': 'Buchanan', 
            'FirstName': 'Steven', 
            'Address': { 
                'No': '1', 
                'StreetName': '17th Avenue', 
                'City': 'London', 
                'Country': 'UK' 
            } 
        } 
    ]; 
 
    function Created() { 
        var qryBldrObj = ej.base.getComponent(document.getElementById("querybuilder"), 'query-builder'); 
        qryBldrObj.dataSource = employeeData; 
    } 
 
    function actionBegin(args) { 
        var qryBldrObj = ej.base.getComponent(document.getElementById("querybuilder"), 'query-builder'); 
        ruleID = args.ruleID; 
        if (args.requestType === 'template-create') { 
            var fieldColl = args.rule.field.split('.'); 
            var elem = document.getElementById(args.ruleID + "_filterkey"); 
            if (!elem.classList.contains("e-dropdownlist")) { 
                fieldObj = new ej.dropdowns.DropDownList({ 
                    dataSource: qryBldrObj.columns, 
                    fields: args.fields, 
                    value: fieldColl[0], 
                    change: function (e) { 
                        qryBldrObj.notifyChange(e.value, e.element, 'field'); 
                    } 
                }); 
                createSubField(fieldObj, args); 
                createOperator(args); 
                createValue(args); 
                fieldObj.appendTo('#' + args.ruleID + '_filterkey'); 
                fieldObj1.appendTo('#' + args.ruleID + '_filterkey1'); 
                operatorObj.appendTo('#' + args.ruleID + '_operatorkey'); 
                textboxObj.appendTo('#' + args.ruleID + '_valuekey0'); 
            } 
        } 
    } 
    var element = document.getElementById('ruleContent'); 
 
    function updateRule(args) { 
        element.textContent = JSON.stringify(args.rule, null, 4); 
    } 
 
    function createSubField(fieldObj, actionBeginArgs) { 
        var qryBldrObj = ej.base.getComponent(document.getElementById("querybuilder"), 'query-builder'); 
        var elem = document.getElementById(actionBeginArgs.ruleID + "_filterkey1"); 
        var fieldColl = actionBeginArgs.rule.field.split('.'); 
        var ds = ['No', 'StreetName', 'City', 'Country']; 
        if (!elem.classList.contains("e-dropdownlist")) { 
            fieldObj1 = new ej.dropdowns.DropDownList({ 
                dataSource: ds, 
                value: fieldColl[1], 
                change: function (e) { 
                    qryBldrObj.notifyChange('Address.' + e.value, e.element, 'field'); 
 
                } 
            }); 
 
        } 
    } 
 
    function createOperator(actionBeginArgs) { 
        var qryBldrObj = ej.base.getComponent(document.getElementById("querybuilder"), 'query-builder'); 
        var elem = document.getElementById(actionBeginArgs.ruleID + "_operatorkey"); 
        if (!elem.classList.contains("e-dropdownlist")) { 
            operatorObj = new ej.dropdowns.DropDownList({ 
                dataSource: customOperator, 
                fields: { text: "key", value: "value" }, 
                value: actionBeginArgs.rule.operator, 
                change: function (e) { 
                    qryBldrObj.notifyChange(e.value, e.element, 'operator'); 
 
                } 
            }); 
 
        } 
    } 
 
 
    function createValue(actionBeginArgs) { 
        var qryBldrObj = ej.base.getComponent(document.getElementById("querybuilder"), 'query-builder'); 
        var elem = document.getElementById(actionBeginArgs.ruleID + "_valuekey0"); 
        if (!elem.classList.contains("e-textbox")) { 
            textboxObj = new ej.inputs.TextBox({ 
                floatLabelType: 'Auto', 
                change: function (e) { 
                    qryBldrObj.notifyChange(e.value, e.container.getElementsByTagName("input")[0], 'value'); 
                } 
            }); 
 
        } 
    } 
</script> 
 
 
For your reference, we have prepared a sample based on this. Please refer below link. 
 
 
In Querybuilder component, column field will be render by dropdown list by default. If you can select any of column field. But rule template, we can define different controls for different columns and the field control created based on the selected field.  
 
Please let us know, if you need any further assistance. 
 
Regards, 
Mohan kumar R 


Marked as answer
Loader.
Up arrow icon