Search results

Data Binding in ASP.NET Core QueryBuilder control

03 Aug 2021 / 3 minutes to read

The Query Builder uses DataManager to bind the data source, which supports both RESTful JSON data services binding and local JavaScript object array binding. The DataSource property can be assigned either with the instance of DataManager or JavaScript object array collection. It supports two kinds of data binding method.

  • Local data
  • Remote data

Local Data

To bind local data to the query builder, you can assign the DataSource property with a JavaScript object array. The local data source can also be provided as an instance of the DataManager.

tagHelper
default.cs
Copied to clipboard
<ejs-querybuilder id="querybuilder" width="73%" rule="ViewBag.rule" dataSource="ViewBag.dataSource">
        <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="TitleOfCourtesy" label="Title Of Courtesy" type="boolean" values="ViewBag.values"></e-querybuilder-column>
            <e-querybuilder-column field="Title" label="Title" type="string"></e-querybuilder-column>
            <e-querybuilder-column field="HireDate" label="Hire Date" type="date" format="dd/MM/yyyy"></e-querybuilder-column>
            <e-querybuilder-column field="Country" label="Country" type="string"></e-querybuilder-column>
            <e-querybuilder-column field="City" label="City" type="string"></e-querybuilder-column>
        </e-querybuilder-columns>
     </ejs-querybuilder>
Copied to clipboard
public ActionResult Index()
    {
          QueryBuilderRule rule = new QueryBuilderRule()
            {
                Condition = "and",
                Rules = new List<QueryBuilderRule>()
                {
                    new QueryBuilderRule { Label="Employee ID", Field="EmployeeID", Type="number", Operator="equal", Value = 1 },
                    new QueryBuilderRule { Label="Title", Field="Title", Type="string", Operator="equal", Value = "Sales Manager" }
                }
            };

            ViewBag.rule = rule;
            ViewBag.dataSource = EmployeeView.GetAllRecords();
            return View();
    }

public class EmployeeView
    {
        public EmployeeView()
        {

        }
        public EmployeeView(int EmployeeID, string FirstName, string LastName, string Title, DateTime BirthDate, DateTime HireDate, int ReportsTo, string Address, string PostalCode, string Phone, string City, string Country)
        {
            this.EmployeeID = EmployeeID;
            this.FirstName = FirstName;
            this.LastName = LastName;
            this.Title = Title;
            this.BirthDate = BirthDate;
            this.HireDate = HireDate;
            this.ReportsTo = ReportsTo;
            this.Address = Address;
            this.PostalCode = PostalCode;
            this.Phone = Phone;
            this.City = City;
            this.Country = Country;

        }
        public int EmployeeID { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public string Title { get; set; }
        public DateTime BirthDate { get; set; }
        public DateTime HireDate { get; set; }

        public int ReportsTo { get; set; }

        public string Address { get; set; }
        public string PostalCode { get; set; }
        public string Phone { get; set; }
        public string City { get; set; }
        public string Country { get; set; }
        public static List<EmployeeView> GetAllRecords()
        {
            List<EmployeeView> Emp = new List<EmployeeView>();
            Emp.Add(new EmployeeView(1, "Nancy", "Davolio", "Sales Representative", new DateTime(1948, 12, 08), new DateTime(1992, 05, 01), 2, "507 - 20th Ave. E.Apt. 2A ", " 98122", "(206) 555-9857 ", "Seattle ", "USA"));
            Emp.Add(new EmployeeView(2, "Andrew", "Fuller", "Vice President, Sales", new DateTime(1952, 02, 19), new DateTime(1992, 08, 14), 4, "908 W. Capital Way", "98401 ", "(206) 555-9482 ", "Kirkland ", "USA"));
            Emp.Add(new EmployeeView(3, "Janet", "Leverling", "Sales Representative", new DateTime(1963, 08, 30), new DateTime(1992, 04, 01), 3, " 4110 Old Redmond Rd.", "98052 ", "(206) 555-8122", "Redmond ", "USA "));
            Emp.Add(new EmployeeView(4, "Margaret", "Peacock", "Sales Representative", new DateTime(1937, 09, 19), new DateTime(1993, 05, 03), 6, "14 Garrett Hill ", "SW1 8JR ", "(71) 555-4848 ", "London ", "UK "));
            Emp.Add(new EmployeeView(5, "Steven", "Buchanan", "Sales Manager", new DateTime(1955, 03, 04), new DateTime(1993, 10, 17), 8, "Coventry HouseMiner Rd. ", "EC2 7JR ", " (206) 555-8122", "Tacoma ", " USA"));
            Emp.Add(new EmployeeView(6, "Michael", "Suyama", "Sales Representative", new DateTime(1963, 07, 02), new DateTime(1993, 10, 17), 2, " 7 Houndstooth Rd.", " WG2 7LT", "(71) 555-4444 ", "London ", "UK "));
            Emp.Add(new EmployeeView(7, "Robert", "King", "Sales Representative", new DateTime(1960, 05, 29), new DateTime(1994, 01, 02), 7, "Edgeham HollowWinchester Way ", "RG1 9SP ", "(71) 555-5598 ", "London ", " UK"));
            Emp.Add(new EmployeeView(8, "Laura", "Callahan", "Inside Sales Coordinator", new DateTime(1958, 01, 09), new DateTime(1994, 03, 05), 9, "722 Moss Bay Blvd. ", "98033 ", " (206) 555-3412", "Seattle ", "USA "));
            Emp.Add(new EmployeeView(9, "Anne", "Dodsworth", "Sales Representative", new DateTime(1966, 01, 27), new DateTime(1994, 11, 15), 5, "4726 - 11th Ave. N.E. ", "98105 ", "(71) 555-5598 ", " London", "UK "));
            return Emp;
        }
    }

By default, DataManager uses JsonAdaptor for local data-binding.

Remote data

To bind remote data to the query builder, assign service data as an instance of DataManager to the dataSource property. To interact with remote data source, provide the endpoint url.

remotedata.cs
Copied to clipboard
public IActionResult Index()
{
        QueryBuilderRule rule = new QueryBuilderRule()
            {
                Condition = "and",
                Rules = new List<QueryBuilderRules>()
                {
                    new QueryBuilderRules { Label="Employee ID", Field="EmployeeID", Type="number", Operator="equal", Value = 1 },
                    new QueryBuilderRules { Label="Title", Field="Title", Type="string", Operator="equal", Value = "Sales Manager" }
                }
            };

            ViewBag.rule = rule;
            return view(); 
}

By default, DataManager uses ODataAdaptor for remote data-binding.

Binding with OData services

OData is a standardized protocol for creating and consuming data. You can retrieve data from OData service using the DataManager. Refer to the following code example for remote Data binding using OData service.

odata.cs
Copied to clipboard
public IActionResult Index()
{
        QueryBuilderRule rule = new QueryBuilderRule()
            {
                Condition = "and",
                Rules = new List<QueryBuilderRules>()
                {
                    new QueryBuilderRules { Label="Employee ID", Field="EmployeeID", Type="number", Operator="equal", Value = 1 },
                    new QueryBuilderRules { Label="Title", Field="Title", Type="string", Operator="equal", Value = "Sales Manager" }
                }
            };

            ViewBag.rule = rule;
            return view(); 
}

Binding with ODatav4 services

The ODatav4 is an improved version of OData protocols, and the DataManager can also retrieve and consume ODatav4 services. For more details on ODatav4 services, refer to the odata documentation. To bind ODatav4 service, use the ODataV4Adaptor.

odatav4.cs
Copied to clipboard
public IActionResult Index()
{
        QueryBuilderRule rule = new QueryBuilderRule()
            {
                Condition = "and",
                Rules = new List<QueryBuilderRules>()
                {
                    new QueryBuilderRules { Label="Employee ID", Field="EmployeeID", Type="number", Operator="equal", Value = 1 },
                    new QueryBuilderRules { Label="Title", Field="Title", Type="string", Operator="equal", Value = "Sales Manager" }
                }
            };

            ViewBag.rule = rule;
            return view(); 
}

Web API

You can use WebApiAdaptor to bind query builder with Web API created using OData endpoint.

webapi.cs
Copied to clipboard
public IActionResult Index()
{
        QueryBuilderRule rule = new QueryBuilderRule()
            {
                Condition = "and",
                Rules = new List<QueryBuilderRules>()
                {
                    new QueryBuilderRules { Label="Employee ID", Field="EmployeeID", Type="number", Operator="equal", Value = 1 },
                    new QueryBuilderRules { Label="Title", Field="Title", Type="string", Operator="equal", Value = "Sales Manager" }
                }
            };

            ViewBag.rule = rule;
            return view(); 
}

Url adaptor

You can use the UrlAdaptor of DataManager when binding data source from remote data. In the initial load of querybuilder, data are fetched from remote data and bound to the querybuilder using url property of DataManager.

url-data.cs
Copied to clipboard
public IActionResult QBDatasource([FromBody]DataManagerRequest dm) 
        { 
            IEnumerable DataSource = employeeData; 
            DataOperations operation = new DataOperations(); 
            if (dm.Where != null && dm.Where.Count > 0) //Filtering 
            { 
                DataSource = operation.PerformFiltering(DataSource, dm.Where, dm.Where[0].Operator); 
            } 
            int count = DataSource.Cast<OrdersDetails>().Count(); 
            if (dm.Skip != 0) 
            { 
                DataSource = operation.PerformSkip(DataSource, dm.Skip);         //Paging 
            } 
            if (dm.Take != 0) 
            { 
                DataSource = operation.PerformTake(DataSource, dm.Take); 
            } 
            return dm.RequiresCounts ? Json(new { result = DataSource, count = count }) : Json(DataSource); 
        }

Support with Data Manager

You can use the created conditions in DataManager through the getPredicate method, which results the filtered records.

tagHelper
default.cs
Copied to clipboard
<ejs-querybuilder id="querybuilder" width="100%" rule="ViewBag.rule">
            <e-querybuilder-columns>
                <e-querybuilder-column field="TaskID" label="Task ID" type="number"></e-querybuilder-column>
                <e-querybuilder-column field="Name" label="Name" type="string"></e-querybuilder-column>
                <e-querybuilder-column field="Category" label="Category" type="string"></e-querybuilder-column>
                <e-querybuilder-column field="SerialNo" label="Serial No" type="string"></e-querybuilder-column>
                <e-querybuilder-column field="InvoiceNo" label="Invoice No" type="string"></e-querybuilder-column>
                <e-querybuilder-column field="Status" label="Status" type="string"></e-querybuilder-column>
            </e-querybuilder-columns>
        </ejs-querybuilder>

<ejs-button id="getpredicate" cssClass='e-primary' content="Get Predicate"></ejs-button>

<script>
  document.getElementById('getpredicate').onclick = function () {
        var querybuilderObj = ej.base.getInstance(document.getElementById("querybuilder"), ej.querybuilder.QueryBuilder);
        var template = '<tr><td>${TaskID}</td><td>${Name}</td><td>${Category}</td></tr>';
        var compileFunction = ej.base.compile(template);
        var table = (document.getElementById('datatable'));
        table.className = 'e-table';
        var predicate = querybuilderObj.getPredicate(querybuilderObj.getValidRules(querybuilderObj.rule));
        dataManagerQuery = new ej.data.Query().select(['TaskID', 'Name', 'Category', 'SerialNo', 'InvoiceNo', 'Status']).where(predicate);
        new ej.data.DataManager(@Html.Raw(JsonConvert.SerializeObject(@ViewBag.DataSource)))
                .executeQuery(dataManagerQuery)
                .then(function (e) {
                    e.result.forEach(function (data) {
                        table.appendChild(compileFunction(data)[0]);
                    });
                });
    }
 </script>
 <style type="text/css">
    .e-hide {
        display: none;
    }
</style>
 <body>
    <div id="container">
        <div id="Grid"></div>
        <table id="datatable" class="e-table e-hide">
            <thead>
               <tr><th>Task ID</th><th>Category</th><th>Name</th></tr>
            </thead>
            <tbody>
            </tbody>    
        </table>        
    </div>

<script>
var ele = document.getElementById('container');
if(ele) {
    ele.style.visibility = "visible";
 }   
        </script>
</body>
Copied to clipboard
public ActionResult Index()
    {
          QueryBuilderRule rule = new QueryBuilderRule()
            {
                Condition = "and",
                Rules = new List<QueryBuilderRule>()
                {
                    new QueryBuilderRule { Label="Category", Field="Category", Type="string", Operator="equal", Value = "Laptop" }
                }
            };

            ViewBag.rule = rule;
            // hardwareData is referred from MVC sample browser.
            ViewBag.DataSource = QueryBuilderData.hardwareData;
            return View();
    }

Grid Integration with QueryBuilder

This section explains how to integrate Grid with QueryBuilder. We have used UrlAdaptor to load dataSource to Grid, and the dataSource property is optional for QueryBuilder. So, you can create QueryBuilder with only columns. QueryBuilder interacts with Grid through the Query property of a Grid. You can get the query from QueryBuilder and update the Grid Query property in the ruleChange event of QueryBuilder. The UrlAdaptor works based on the on-demand concept, it will load only current page records from the server and request the next page records when navigating to the next page. Also, we have sent the request to the server for every action performed in the Grid.

tagHelper
HomeController.cs
Copied to clipboard
<ejs-querybuilder id="querybuilder" width="73%" ruleChange="updateRule">
        <e-querybuilder-columns>
            <e-querybuilder-column field="CustomerID" label="Customer ID" type="number"></e-querybuilder-column>
            <e-querybuilder-column field="CompanyName" label="Company Name" type="string"></e-querybuilder-column>
            <e-querybuilder-column field="ContactName" label="Contact Name" type="string"></e-querybuilder-column>
            <e-querybuilder-column field="City" label="City" type="string"></e-querybuilder-column>
        </e-querybuilder-columns>
    </ejs-querybuilder>

 <ejs-grid id="grid" allowPaging="true">
     <e-data-manager url="/Home/UrlDataSource" adaptor="UrlAdaptor"></e-data-manager>
     <e-grid-columns>
         <e-grid-column field="CustomerID" headerText="Customer ID" width="120">  </e-grid-column>
         <e-grid-column field="CompanyName" headerText="Company Name" width="120"></e-grid-column>
         <e-grid-column field="ContactName" headerText="Contact Name" width="100"></e-grid-column>
         <e-grid-column field="City" headerText="City" width="120"></e-grid-column>
     </e-grid-columns>
 </ejs-grid>

<script>

    function updateRule(args) {
        var dataManagerQuery;
        var qryBldrObj  = ej.base.getComponent(document.getElementById("querybuilder"), 'query-builder');
        var grid = ej.base.getComponent(document.getElementById("grid"), 'grid');
        var predicate = qryBldrObj.getPredicate(args.rule);
        if (ej.base.isNullOrUndefined(predicate)) {
            dataManagerQuery = new ej.data.Query().select(['CustomerID', 'CompanyName', 'ContactName', 'City']);
         } else {
            dataManagerQuery = new ej.data.Query().select(['CustomerID', 'CompanyName', 'ContactName', 'City']).where(predicate);
         }
            grid.query = dataManagerQuery;
            grid.refresh();
    }
</script>
Copied to clipboard
public class HomeController : Controller
{
    private NORTHWNDContext _context;
    public HomeController(NORTHWNDContext context)
    {
        _context = context;
    }

    public IActionResult Index()
    {
        return View();
    }

    private IQueryable<Records> GetDataSource()
    {
        IQueryable<Records> transactions = _context.Records;

        return transactions;
    }

    public IActionResult UrlDatasource([FromBody] DataManagerRequest dm)
    {
        IQueryable<Records> DataSource = GetDataSource();
        QueryableOperation operation = new QueryableOperation();
        if (dm.Where != null && dm.Where.Count > 0) //Filtering
        {
            DataSource = operation.PerformFiltering(DataSource, dm.Where, dm.Where[0].Condition);  //filtering
        }
        if (dm.Search != null && dm.Search.Count > 0)
        {
            DataSource = operation.PerformSearching(DataSource, dm.Search);  //Search
        }
        int count = DataSource.Cast<Records>().Count();
        if (dm.Skip != 0)
        {
            DataSource = operation.PerformSkip(DataSource, dm.Skip);
        }
        if (dm.Take != 0)
        {
            DataSource = operation.PerformTake(DataSource, dm.Take);
        }
        return dm.RequiresCounts ? Json(new { result = DataSource, count = count }) : Json(DataSource);
    }
}