How do determine when DataSource is no longer used - javascript

I have a page with a Kendo Grid. When the user selects a row in the Grid I update a template and another grid with dependent information. I'm doing this by creating two new DataSources and binding them (see the code below).
To support live updates I want to attach, in the init() of the DataSource, an event handler to a websocket to detect changes in the backend for this DataSource (basically a subscription model). My problem is that in this page since every time the user selects an item I would get two more DataSources and so I would end up with lots of event handlers triggering for DataSources that are no longer used. I would like to clean them up somehow.
I can see a number of ways to handle this:
Have some event that triggers when the DataSource is no longer used so I can unregister the handler and unsubscribe.
Instead of creating a new DataSource each time just change the url in the transport each time. But then I'd like some event that triggers when the transport is changed so the event handler knows the subscription needs to be changed.
What I currently do: add a custom method to the DataSource called nuke() which I call just before creating the new DataSource. Error prone, but functional.
Or am I going about this completely the wrong way? Perhaps there is some general way to trigger on changes in Kendo objects?
Below is code that demonstrates the naive approach that causes the problem. It's also available here: http://dojo.telerik.com/OKaDu
Note the example code uses filters but in my actual code it's the URL that changes. Though if there is a way to trigger on changing filters that would be cool too.
<html>
<head>
<meta charset="utf-8">
<title>Kendo UI Snippet</title>
<link rel="stylesheet" href="http://kendo.cdn.telerik.com/2015.2.624/styles/kendo.common.min.css">
<link rel="stylesheet" href="http://kendo.cdn.telerik.com/2015.2.624/styles/kendo.rtl.min.css">
<link rel="stylesheet" href="http://kendo.cdn.telerik.com/2015.2.624/styles/kendo.default.min.css">
<link rel="stylesheet" href="http://kendo.cdn.telerik.com/2015.2.624/styles/kendo.dataviz.min.css">
<link rel="stylesheet" href="http://kendo.cdn.telerik.com/2015.2.624/styles/kendo.dataviz.default.min.css">
<link rel="stylesheet" href="http://kendo.cdn.telerik.com/2015.2.624/styles/kendo.mobile.all.min.css">
<script src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
<script src="http://kendo.cdn.telerik.com/2015.2.624/js/kendo.all.min.js"></script>
</head>
<body>
<div id="grid"></div>
<div id="detail">
Employee ID: <span data-bind="text: EmployeeID"></span><br>
FirstName: <span data-bind="text: FirstName"></span><br>
LastName: <span data-bind="text: LastName"></span><br>
</div>
<div id="orders"></div>
<script>
var element = $("#grid").kendoGrid({
dataSource: {
type: "odata",
transport: {
read: "http://demos.kendoui.com/service/Northwind.svc/Employees"
},
pageSize: 6,
serverPaging: true,
serverSorting: true
},
height: 450,
selectable: "row",
sortable: true,
pageable: true,
columns: [
{
field: "FirstName",
title: "First Name"
},
{
field: "LastName",
title: "Last Name"
},
{
field: "Country"
},
{
field: "City"
},
{
field: "Title"
}
],
change: function(e) {
var selectedRows = this.select();
var dataItem = this.dataItem(selectedRows[0]);
var remoteDataSource = new kendo.data.DataSource({
type: "odata",
transport: {
read: "http://demos.kendoui.com/service/Northwind.svc/Employees"
},
serverPaging: true,
serverSorting: true,
serverFiltering: true,
pageSize:6,
filter: { field: "EmployeeID", operator: "eq", value: dataItem.EmployeeID }
});
remoteDataSource.fetch(function(){
kendo.bind("#detail", remoteDataSource.view()[0]);
});
$("#orders").kendoGrid({
dataSource: {
type: "odata",
transport: {
read: "http://demos.kendoui.com/service/Northwind.svc/Orders"
},
serverPaging: true,
serverSorting: true,
serverFiltering: true,
pageSize:6,
filter: { field: "EmployeeID", operator: "eq", value: dataItem.EmployeeID }
},
scrollable: false,
sortable: true,
pageable: true,
columns: [
{ field: "OrderID", width: 70 },
{ field: "ShipCountry", title:"Ship Country", width: 100 },
{ field: "ShipAddress", title:"Ship Address" },
{ field: "ShipName", title: "Ship Name", width: 200 }
]
});
}
});
</script>
</body>
</html>

Related

Kendo grid make detailinit expand and checkbox selected when select master table

I create a similar demo relate with my situation. What I want to achieve when checked on the master grid, the details grid will expand and all the checkbox inside it will be checked and also the child grid is selected.
It's possible to do like this without using column template for the checkbox.
DEMO IN DOJO
Example like this screen shot. (this one manually checked)
p/s: I found a similar demo, but this one using column.template for the checkbox.
This example code (which is based on your sample code) answers your requirement, which is...
What I want to achieve when checked on the master grid, the details grid will expand and all the checkbox inside it will be checked and also the child grid is selected.
Try this in the Telerik DOJO. We need to wait for Kendo to finish expanding the detail row (making sure all HTML elements are fully built), hence the setTimeout in detailExpand. Change the delay depending on your needs.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Kendo Grid Master Detail Checkbox</title>
<link rel="stylesheet" href="https://kendo.cdn.telerik.com/2020.3.1118/styles/kendo.default-v2.min.css"/>
<script src="https://code.jquery.com/jquery-1.12.3.min.js"></script>
<script src="https://kendo.cdn.telerik.com/2021.2.616/js/kendo.all.min.js"></script></head>
<body>
<div id="example">
<div id="grid"></div>
<script>
$(document).ready(function() {
var grid = $("#grid").kendoGrid({
dataSource: {
type: "odata",
transport: {
read: "https://demos.telerik.com/kendo-ui/service/Northwind.svc/Employees"
},
pageSize: 6,
serverPaging: true,
serverSorting: true
},
height: 600,
sortable: true,
pageable: true,
detailInit: detailInit,
detailExpand: function(e) {
var $checkbox = $(e.masterRow.context);
if ($checkbox.is(":checked")) {
setTimeout(function() {
e.detailRow.find("tbody tr").each(function() {
var $row = $(this);
$row.find(".k-checkbox").each(function() {
var $checkbox = $(this);
$checkbox.attr("checked", true);
});
$(this).addClass("k-state-selected");
});
}, 250);
}
},
columns: [
{ selectable: true, width: 50 },
{
field: "FirstName",
title: "First Name",
width: "110px"
},
{
field: "LastName",
title: "Last Name",
width: "110px"
},
{
field: "Country",
width: "110px"
},
{
field: "City",
width: "110px"
},
{
field: "Title"
}
]
}).data("kendoGrid");
grid.tbody.on("click", ".k-master-row .k-checkbox", function(e) {
var $checkbox = $(this);
if ($checkbox.is(":checked")) {
var $tr = $checkbox.closest("tr");
var $a = $tr.find(".k-hierarchy-cell a.k-icon");
if ($a.length) {
if ($a.hasClass("k-i-expand")) {
grid.expandRow($tr);
}
}
}
});
});
function detailInit(e) {
var detailgrid = $("<div/>").appendTo(e.detailCell).kendoGrid({
dataSource: {
type: "odata",
transport: {
read: "https://demos.telerik.com/kendo-ui/service/Northwind.svc/Orders"
},
serverPaging: true,
serverSorting: true,
serverFiltering: true,
pageSize: 10,
filter: {
field: "EmployeeID",
operator: "eq",
value: e.data.EmployeeID
}
},
scrollable: false,
sortable: true,
pageable: true,
columns: [
{ selectable: true, width: 50, headerTemplate: ' '},
{
field: "OrderID",
width: "110px"
},
{
field: "ShipCountry",
title: "Ship Country",
width: "110px"
},
{
field: "ShipAddress",
title: "Ship Address"
},
{
field: "ShipName",
title: "Ship Name",
width: "300px"
}
]
}).data("kendoGrid");
}
</script>
</div>
</body>
</html>
I adapted your first snippet based on the second one that you provided. Check out this revised demo.
Basically, you need to call getKendoGrid() and assign its return value (the actual grid) to the grid variable.
After that, add the change event listener as shown in the second demo snippet that you provided.
grid.tbody.on("change", ".k-checkbox", function() {
var checkbox = $(this);
var nextRow = checkbox.closest("tr").next();
// Note: the row should be expanded at least once as otherwhise there will be no child grid loaded
if (nextRow.hasClass("k-detail-row")) {
// And toggle the checkboxes
nextRow.find(":checkbox")
.prop("checked", checkbox.is(":checked"));
}
});
Also note that it's not .master as in the second demo, but .k-checkbox, as you are not providing a template in the first column (which the second demo does and the checkbox there has the master class).

Javascript AG-Grid Fetching and Displaying Data

I am trying to display data from an AJAX call in AG Grid and no data is being displayed. I can see my AJAX call is working as expected because the result contains the object List that I want to show, but no grid is even appearing.
Below is my code for Index.cshtml. Below that is my Inv.js and the result is the return from the AJAX call.
<script src="https://unpkg.com/ag-grid-community/dist/ag-grid-community.min.noStyle.js"></script>
<link rel="stylesheet" href="https://unpkg.com/ag-grid-community/dist/styles/ag-grid.css">
<link rel="stylesheet" href="https://unpkg.com/ag-grid-community/dist/styles/ag-theme-balham.css">
<div id="Inventory" width="100%" class="ag-theme-balham"></div>
var columnDefs = [
{ headerName: "ID", field: "ID", sortable: true, filter: true },
{ headerName: "InvID", field: "InvID", sortable: true, filter: true },
{ headerName: "Number", field: "Number", sortable: true, filter: true }
];
var gridOptions = {
columnDefs: columnDefs
};
var gridDiv = document.querySelector('#Inventory');
new agGrid.Grid(gridDiv, gridOptions);
gridOptions.api.setRowData(result);
<div id="Inventory" style="width:100%; height:100%;" class="ag-theme-balham"></div>
I had to add a height attribute to my div and now the grid shows.

Problem in setGridWidth method with ‘shrinktofit’ parameter set to’ true’ in Guriddo jqGrid with Bootstrap

Using setGridWidth method on jqGrid with ‘shrinktofit’ parameter ‘true’ when using with Bootstrap causes an unnecessary horizontal scrollbar to appear when number of records is less (i.e. without vertical scrollbar).
The horizontal scrollbar disappears as soon as records are more (i.e. with vertical scrollbar).
To demonstrate the problem I have called setGridWidth method on Loadcomplete
I have even replicated the problem on jsfiddle: http://jsfiddle.net/yoabhinav/uqonspmd/
Here is a fiddle with setGridWidth method call inside Loadcomplete event commented which works fine as expected: http://jsfiddle.net/yoabhinav/knuj9xet/
$(document).ready(function () {
const data = { "rows":[{"OrderID":"1","CustomerID":"WILMK","OrderDate":"1996-07-04 00:00:00","Freight":"32.3800","ShipName":"Vins et alcools Chevalier"},{"OrderID":"2","CustomerID":"TRADH","OrderDate":"1996-07-05 00:00:00","Freight":"11.6100","ShipName":"Toms Spezialit\u00e4ten"},{"OrderID":"3","CustomerID":"HANAR","OrderDate":"1996-07-08 00:00:00","Freight":"65.8300","ShipName":"Hanari Carnes"},{"OrderID":"4","CustomerID":"VICTE","OrderDate":"1996-07-08 00:00:00","Freight":"41.3400","ShipName":"Victuailles en stock"},{"OrderID":"5","CustomerID":"SUPRD","OrderDate":"1996-07-09 00:00:00","Freight":"51.3000","ShipName":"Supr\u00eames d\u00e9lices"},{"OrderID":"6","CustomerID":"HANAR","OrderDate":"1996-07-10 00:00:00","Freight":"58.1700","ShipName":"Hanari Carnes"},{"OrderID":"7","CustomerID":"CHOPS","OrderDate":"1996-07-11 00:00:00","Freight":"22.9800","ShipName":"Chop-suey Chinese"},{"OrderID":"8","CustomerID":"RICSU","OrderDate":"1996-07-12 00:00:00","Freight":"148.3300","ShipName":"Richter Supermarkt"},{"OrderID":"9","CustomerID":"WELLI","OrderDate":"1996-07-15 00:00:00","Freight":"13.9700","ShipName":"Wellington Importadora"},{"OrderID":"10","CustomerID":"HILAA","OrderDate":"1996-07-16 00:00:00","Freight":"81.9100","ShipName":"HILARI\u00d3N-Abastos"},{"OrderID":"11","CustomerID":"ERNSH","OrderDate":"1996-07-17 00:00:00","Freight":"140.5100","ShipName":"Ernst Handel"},{"OrderID":"12","CustomerID":"CENTC","OrderDate":"1996-07-18 00:00:00","Freight":"3.2500","ShipName":"Centro comercial Moctezuma"},{"OrderID":"13","CustomerID":"OLDWO","OrderDate":"1996-07-19 00:00:00","Freight":"55.0900","ShipName":"Ottilies K\u00e4seladen"},{"OrderID":"14","CustomerID":"QUEDE","OrderDate":"1996-07-19 00:00:00","Freight":"3.0500","ShipName":"Que Del\u00edcia"},{"OrderID":"15","CustomerID":"RATTC","OrderDate":"1996-07-22 00:00:00","Freight":"48.2900","ShipName":"Rattlesnake Canyon Grocery"},{"OrderID":"16","CustomerID":"ERNSH","OrderDate":"1996-07-23 00:00:00","Freight":"146.0600","ShipName":"Ernst Handel"},{"OrderID":"17","CustomerID":"FOLKO","OrderDate":"1996-07-24 00:00:00","Freight":"3.6700","ShipName":"Folk och f\u00e4 HB"},{"OrderID":"18","CustomerID":"BLONP","OrderDate":"1996-07-25 00:00:00","Freight":"55.2800","ShipName":"Blondel p\u00e8re et fils"},{"OrderID":"19","CustomerID":"WARTH","OrderDate":"1996-07-26 00:00:00","Freight":"25.7300","ShipName":"Wartian Herkku"},{"OrderID":"20","CustomerID":"FRANK","OrderDate":"1996-07-29 00:00:00","Freight":"208.5800","ShipName":"Frankenversand"}]
}
$("#jqGrid").jqGrid({
pager: "#jqGridPager",
datastr: data,
datatype: "jsonstring",
styleUI : 'Bootstrap',
colModel: [
{ label: 'OrderID', name: 'OrderID', key: true, width: 75 },
{ label: 'Customer ID', name: 'CustomerID', width: 150 },
{ label: 'Order Date', name: 'OrderDate', width: 150 },
{ label: 'Freight', name: 'Freight', width: 150 },
{ label:'Ship Name', name: 'ShipName', width: 150 }
],
viewrecords: true,
height: 250,
rowNum: 5,
autowidth: true,
shrinkToFit: true,
rownumbers: true,
gridview: false,
loadComplete: function () {
const parent_width = $("#jqGrid").parent().width();
$("#jqGrid").jqGrid('setGridWidth', parent_width);
}
});
});
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css" rel="stylesheet"/>
<link href="http://www.guriddo.net/demo/css/trirand/ui.jqgrid-bootstrap.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script src="http://www.guriddo.net/demo/js/trirand/i18n/grid.locale-en.js"></script>
<script src="http://www.guriddo.net/demo/js/trirand/src/jquery.jqGrid.js"></script>
<div>
<table id="jqGrid"></table>
<div id="jqGridPager"></div>
</div>
This problem is fixed and will be available in the next release. If this is a showstopper for you can get the fixed code from GitHub.
UPDATE: The code used in loadComplete can be avoided if you just set responsive option in jqGrid set to true. I recommend you to to consult the documentation here

Kendo grid events not working with delegates

I have a page that may create several grids at any time. I am trying to set a single event handler for all of them by adding a delegate for the groupor dataBoundevent but it never triggers.
I am trying this
$(document).on('dataBound', 'div.k-grid', onGridDataBound);
Is it possible to do this without hooking on to each individual grid's settings when it is being created or without having to bind the event per grid?
I can suggest you two alternatives:
Override the Grid prototype (before creating any Grids) and inject the event handler(s) directly there:
function onGridDataBound(e) {
alert(e.sender.wrapper.attr("id") + " was databound");
}
kendo.ui.Grid.fn.options.dataBound = onGridDataBound;
Here is a full example:
<!DOCTYPE html>
<html>
<head>
<base href="http://demos.telerik.com/kendo-ui/grid/remote-data-binding">
<style>html { font-size: 14px; font-family: Arial, Helvetica, sans-serif; }</style>
<title></title>
<link rel="stylesheet" href="https://kendo.cdn.telerik.com/2017.2.621/styles/kendo.common.min.css" />
<link rel="stylesheet" href="https://kendo.cdn.telerik.com/2017.2.621/styles/kendo.default.min.css" />
<script src="https://kendo.cdn.telerik.com/2017.2.621/js/jquery.min.js"></script>
<script src="https://kendo.cdn.telerik.com/2017.2.621/js/kendo.all.min.js"></script>
</head>
<body>
<p>Grid 1</p>
<div id="grid1"></div>
<p>Grid 2</p>
<div id="grid2"></div>
<script>
function onGridDataBound(e) {
alert(e.sender.wrapper.attr("id") + " was databound");
}
$(function() {
kendo.ui.Grid.fn.options.dataBound = onGridDataBound;
var gridOptions = {
dataSource: {
type: "odata",
transport: {
read: "https://demos.telerik.com/kendo-ui/service/Northwind.svc/Orders"
},
pageSize: 5,
serverPaging: true,
serverFiltering: true,
serverSorting: true
},
height: 200,
pageable: true,
columns: [{
field:"OrderID",
filterable: false
}, {
field: "ShipName",
title: "Ship Name"
}, {
field: "ShipCity",
title: "Ship City"
}]
};
$("#grid1").kendoGrid(gridOptions);
$("#grid2").kendoGrid(gridOptions);
});
</script>
</body>
</html>
Create a custom Kendo UI widget that has the desired event handlers attached initially.
(function($) {
var kendo = window.kendo,
ui = kendo.ui,
Grid = ui.Grid
var MyGrid = Grid.extend({
init: function(element, options) {
Grid.fn.init.call(this, element, options);
this.bind("dataBound", onGridDataBound);
},
options: {
name: "MyGrid"
}
});
ui.plugin(MyGrid);
})(jQuery);
function onGridDataBound(e) {
alert(e.sender.wrapper.attr("id") + " was databound");
}
Here is a full example:
<!DOCTYPE html>
<html>
<head>
<base href="http://demos.telerik.com/kendo-ui/grid/remote-data-binding">
<style>html { font-size: 14px; font-family: Arial, Helvetica, sans-serif; }</style>
<title>Kendo UI default event handlers via prototype</title>
<link rel="stylesheet" href="https://kendo.cdn.telerik.com/2017.2.621/styles/kendo.common.min.css" />
<link rel="stylesheet" href="https://kendo.cdn.telerik.com/2017.2.621/styles/kendo.default.min.css" />
<script src="https://kendo.cdn.telerik.com/2017.2.621/js/jquery.min.js"></script>
<script src="https://kendo.cdn.telerik.com/2017.2.621/js/kendo.all.min.js"></script>
</head>
<body>
<p>Grid 1</p>
<div id="grid1"></div>
<p>Grid 2</p>
<div id="grid2"></div>
<script>
(function($) {
var kendo = window.kendo,
ui = kendo.ui,
Grid = ui.Grid
var MyGrid = Grid.extend({
init: function(element, options) {
Grid.fn.init.call(this, element, options);
this.bind("dataBound", onGridDataBound);
},
options: {
name: "MyGrid"
}
});
ui.plugin(MyGrid);
})(jQuery);
function onGridDataBound(e) {
alert(e.sender.wrapper.attr("id") + " was databound");
}
$(function() {
var gridOptions = {
dataSource: {
type: "odata",
transport: {
read: "https://demos.telerik.com/kendo-ui/service/Northwind.svc/Orders"
},
pageSize: 5,
serverPaging: true,
serverFiltering: true,
serverSorting: true
},
height: 200,
pageable: true,
columns: [{
field:"OrderID",
filterable: false
}, {
field: "ShipName",
title: "Ship Name"
}, {
field: "ShipCity",
title: "Ship City"
}]
};
$("#grid1").kendoMyGrid(gridOptions);
$("#grid2").kendoMyGrid(gridOptions);
});
</script>
</body>
</html>
So I ended up doing something really inefficient to get this done. Since only the default browser events seem to be delegated, I ended up adding a binder for mousedown on any of the grid headers. The handler for that would then bind to the group event for that grid since then it is guaranteed to be on the page.
var boundGrids = [];
function onGridGroup(e) {
//Grid group code
};
function onGridHeaderClick(e) {
var grid = $(this).closest('.k-grid').data('kendoGrid');
if (!grid._attachedGroup) {
grid._attachedGroup = true;
boundGrids.push(grid);
grid.bind('group', onGridGroup);
}
};
$(document).on('mousedown', '.k-grid th a.k-link', onGridHeaderClick);
Check this thread. Only difference is that in your case you got multiple grids. Due that I would do something like:
var grids = $('div.k-grid');
grids.each(function(e) {
var grid = $(this).data('kendoGrid');
grid.bind("dataBound", function () {
alert('Databounded');
});
});

AngularJS kendo grid with custom command which includes template doesn't handle events

I have an angularjs - kendo UI grid-based solution. In the controller for the grid I have placed the following code:
$scope.customClick = function(e) {
$scope.$apply(
function() {
e.preventDefault();
alert('customClick');
});
};
$scope.gridOptions = {
dataSource: $scope.gridData,
pageable: {
refresh: true,
pageSizes: true,
buttonCount: 5
},
scrollable: true,
sortable: true,
filterable: true,
selectable: true,
editable: "inline",
columns: [
{
command :[ {text: "", template: '<input type="checkbox" id="check-all" />', click: $scope.customClick} ]
},
{field: "DocumentKey", title: "Document Key"},
{field: "Sender", title: "Sender"},
{field: "Recipient", title: "Recipient"},
{field: "ChangeDate", title: "ReceivedBy Time"},
{field: "FlowComment", title: "Comment"},
{field: "Location", title: "Location"}
]
};
});
Added checkbox is displayed fine, but I don't know how to handle the click event. $scope.customClick is not triggered after clicking on check box.
A fairly old question, the user had probably found a solution long ago, but in case google search gets someone to this question, it's good to have an answer. JavaScript combined with libraries like KendoUI and AngularJS usually allow us to solve problems by using several different approaches, but here is one of them:
Say you have a grid defined like this:
<div kendo-grid="kendo.myGrid" k-options="gridOptions"></div>
Your JavaScript code to define this grid might look like this:
$scope.gridOptions = {
dataSource: new kendo.data.DataSource({
data: dataFromSomeLocalVariableMaybe,
pageSize: 10
}),
sortable: true,
pageable: {
pageSizes: [10, 20, 50]
},
columns: [{
field: "column1",
title: "Column 1",
width: "100px"
}, {
field: "column2",
title: "Column 2",
width: "120px"
}, {
command: [{
template: "<span class='k-button' ng-click='doSomething($event)'> Do something</span>"
}, {
template: "<span class='k-button' ng-click='doSomethingElse($event)'> Do something else</span>"
}],
title: " ",
width: "100px"
}]
};
Notice the $event that is passed to ng-click call to a function. That $event contains the actual click event data.
If it would be like this, then you would need to have these two functions defined:
$scope.doSomething = function($event) {
// Get the element which was clicked
var sender = $event.currentTarget;
// Get the Kendo grid row which contains the clicked element
var row = angular.element(sender).closest("tr");
// Get the data bound item for that row
var dataItem = $scope.kendo.myGrid.dataItem(row);
console.log(dataItem);
};
$scope.doSomethingElse = function($event) {
// Do something else
};
And that's it.
Omit $scope.
It should as follows:
{ command : {text: "", click:customClick}, template: '<input type="checkbox" id="check-all"/>}
Your command template should include ng directive, in your case ng-change for the checkbox input, which would point to your target function:
{
command :[{
text: "",
template: '<input type="checkbox" id="check-all" ng-change="customClick"/>'
}]
}

Categories