Kendo UI dataSource changed event: is it working? - events

Is the dataSource.changed event working?
After my Kendo UI grid is instantiated, I am binding the change event per the documentation here:
http://docs.kendoui.com/api/framework/datasource#change
//To set after initialization
dataSource.bind("change", function(e) {
// handle event
});
I am doing this:
// initialize
$("#grid").kendoGrid({
dataSource: dataSource,
blah blah blah
)
});
// end of initialization
// bind afterwards
var grid = $('#grid').data('kendoGrid');
grid.dataSource.bind("change", function (e) {
dataChanged();
});
//also tried a setTimeout:
// bind afterwards
setTimeout(function () {
var grid = $('#grid').data('kendoGrid');
grid.dataSource.bind("change", function (e) {
dataChanged();
});
}, 350);
function dataChanged() {
// handle "change" whatever that means -- documentation definition is hazy
// does reassigning the data array constitute a change?
// does changing the value of a particular item in the data array
// constitute a change?
// does removing an item from the data array constitute a change?
var grid = $("#grid").data("kendoGrid");
grid.refresh();
}
But my dataChanged() function is not called when I do either of these things:
var grid = $('#grid').data('kendoGrid');
grid.dataSource.data()[1]["deptname"] = 'XXX';
or
grid.dataSource.data = aDifferentArray;
I am not sure exactly what the 'changed' event is listening for. What, precisely, is supposed to trigger it?
If I create a completely new dataSource, and assign it to the grid that already has a dataSource, I don't see how that would trigger an existing data source's changed event. Such an event (the grid noticing that its dataSource has been replaced with a different one) would be a grid-level event, not a dataSource-level event, right?

The important thing to note is that the data backing the DataSource is an ObservableArray, and that the data items in that array are converted to ObservableObjects.
The change event of the datasource is fired under 2 conditions:
The data ObservableArray changes (a record is inserted, deleted). An example of this would be using the DataSource.add() or DataSource.remove() functions.
If a property changed event bubbles up to the DataSource from one of the ObservableData objects in the array. However, just like the rest of the Kendo MVVM framework, the notification that a property changed only occurs when its .set("propertyName", value) function is called.
This is why grid.dataSource.data()[1]["deptname"] = 'XXX'; is not triggering the change event. If you change it to: grid.dataSource.data()[1].set("deptname", 'XXX'); then it should start to work. Basically, think of the change event as being fired in response to an MVVM property change fired from the data observable object.
As for changing the data array grid.dataSource.data = aDifferentArray; I'm actually not sure if that will or should trigger a change. I've never tried that.

Related

Kendo UI. Reset Grid to first page after sort changed

I'm using Kendo UI Grid with server paging and sorting. When sort is changed, grid refreshes the data, but current page remains the same.
How to catch sort event and move to first page?
P.S. I've read this thread, but there discussed another case...
Consider the following approach:
use the change event of the Kendo UI DataSource to save the current sort state in some variable.
use the requestStart event to compare the previous sort state with the new sort state.
if the sort state has changed, prevent the request with e.preventDefault()
use the page method to navigate to first page
you will also need a flag variable to prevent an endless loop in the requestStart handler, as changing the page will trigger a new requestStart event
Here is a demo:
http://dojo.telerik.com/OXoYu
var sortState;
var resetPageFlag = false;
// ...
requestStart: function(e) {
//console.log(e.sender.sort(), sortState);
if (!resetPageFlag &&
JSON.stringify(e.sender.sort()) != JSON.stringify(sortState)) {
//console.log(e.sender.sort(), sortState);
e.preventDefault();
resetPageFlag = true;
e.sender.page(1);
} else {
resetPageFlag = false;
}
},
change: function(e) {
sortState = e.sender.sort();
}
// ...

Getting Kendo Grid from its DataSource

I'm writing a generic error handler for all of the Kendo Grids. I need to get that source Grid to prevent its default behavior in saving data. In the handler, you can access the source's DataSouce by args.sender. How can I access the Kendo Grid from that DataSouce?
The only approach I found was this suggestion, searching through all grids, and the handler looks like below, can you suggest anything better and more efficient?
function genericErrorHandler(args) {
if (args.errors) {
$('.k-grid').each(function () {
var grid = $(this).data('kendoGrid');
if (grid.dataSource == args.sender) {
alert('found!');
}
})
}
}
There is no API to get Grid object from data source, but there is many approach beside that.
You can create generic grid's edit event and storing in global scope variable which grid's ID was triggered that event. I prefer to do this rather than compare mutable data source.
var window.currentGrid = "";
function onGenericGridEdit(e) {
window.currentGrid = e.sender;
}
If in some cases you need to make custom edit function, just call your generic edit function in the end of the code.
function onCustomGridEdit(e) {
// call generic function to store
onGenericGridEdit(e);
}

Add or trigger event after inner content to page

I have links on a table to edit or delete elements, that elements can be filtered. I filtered and get the result using ajax and get functions. After that I added (display) the result on the table using inner.html, the issue here is that after filtering the links on the elements not work, cause a have the dojo function like this
dojo.ready(function(){
dojo.query(".delete-link").onclick(function(el){
var rowToDelete = dojo.attr(this,"name");
if(confirm("Really delete?")){
.......
}
});
I need to trigger the event after filtering, any idea?
(I'm assuming that you're using Dojo <= 1.5 here.)
The quick answer is that you need to extract the code in your dojo.ready into a separate function, and call that function at the end of your Ajax call's load() callback. For example, make a function like this:
var attachDeleteEvents = function()
dojo.query(".delete-link").onclick(function(el){
var rowToDelete = dojo.attr(this,"name");
if(confirm("Really delete?")){
.......
}
});
};
Then you call this function both in dojo.ready and when your Ajax call completes:
dojo.ready(function() { attachDeleteEvents(); });
....
var filter = function(someFilter) {
dojo.xhrGet({
url: "some/url.html?filter=someFilter",
handleAs: "text",
load: function(newRows) {
getTableBody().innerHTML = newRows;
attachDeleteEvents();
}
});
};
That was the quick answer. Another thing that you may want to look into is event delegation. What happens in the code above is that every row gets an onclick event handler. You could just as well have a single event handler on the table itself. That would mean there would be no need to reattach event handlers to the new rows when you filter the table.
In recent versions of Dojo, you could get some help from dojo/on - something along the lines of:
require(["dojo/on"], function(on) {
on(document.getElementById("theTableBody"), "a:click", function(evt) {...});
This would be a single event handler on the whole table body, but your event listener would only be called for clicks on the <a> element.
Because (I'm assuming) you're using 1.5 or below, you'll have to do it a bit differently. We'll still only get one event listener for the whole table body, but we have to make sure we only act on clicks on the <a> (or a child element) ourselves.
dojo.connect(tableBody, "click", function(evt) {
var a = null, name = null;
// Bubble up the DOM to find the actual link element (which
// has the data attribute), because the evt.target may be a
// child element (e.g. the span). We also guard against
// bubbling beyond the table body itself.
for(a = evt.target;
a != tableBody && a.nodeName !== "A";
a = a.parentNode);
name = dojo.attr(a, "data-yourapp-name");
if(name && confirm("Really delete " + name + "?")) {
alert("Will delete " + name);
}
});
Example: http://fiddle.jshell.net/qCZhs/1/

How can you determine if KendoUI Grid is in a grouped state?

I need to perform an action on my page when the KendoUI grid has been collapsed. I know that the dataBound event fires when the grid is grouped however this event is fired when the grid loads or gets sorted as well. Within my onDataBound event handler how can I tell if the grid is in a grouped state or not.
On DataBound event you can check if the grid currently is grouped using the DataSource group method:
function onDataBound(e) {
gridDataSource = e.sender.dataSource;
if (gridDataSource.group().length > 0) {
//the grid is grouped
debugger;
}
}
To get notified when a group is collapsed you can use delegate event such as:
$('#gridName tbody').on('click','.k-i-collapse',function(){
console.log('Group collapsed!')
})

Prototype-style of JQuery element observer

I need to replace old event listener code with a new, but without deleting old:
onchange="func1();func2();"
need to be replace by:
onchange="newFunc();func1();func2();"
Adding new code to element's onChange event via JQuery was simple:
var element = $('element');
var _onchange = element.onchange;
element.onchange = function() {
//some additional code
if (typeof(_onchange) == 'function') {
_onchange();
}
};
Now I need to rewrite it using Prototype.. I suppose it will be like:
element.observe('change', function() {
// new code here
// then old onChange
}.bindAsEventListener(element)));
How can I grab existing onChange's code?..
You actually don't need to .bindAsEventListener() except in rare cases
so adding the event observing to an element
$('element').observe('change',function(){
//onchange code
});
If you do this - it will add the new code as an observer without deleting any other observers setup for that element and event

Resources