How do I determine which DataView generated an event? - events

I'm implementing filtering via the HeaderRow of my grids, and I've run across a problem I can't seem to solve.
All the examples that show dataView Event handlers employ global variables to identify the related grid, such as in:
gridQMsgsDataView.onRowCountChanged.subscribe(rowCountChanged);
(...elsewhere...)
function rowCountChanged(e, args) {
grid.updateRowCount(); //'grid' is a global variable assigned to a slickGrid.
grid.render();
}
Unlike in the examples that I find, I'm creating slickjGrids and dataViews dynamically at runtime, and keep their reference variables in a list as I create them.
I can't tell at compile time how many there will be, thus I can't use something like the global "grid" variable to reference the relevant dataview and/or slickgrid.
So I have two questions, and appreciate any insight:
when my rowCountChanged handler is called...
A) How do I know which dataView generated the event?
B) Once I know that, how do I know which slickgrid that dataView is associated with?

A) rowCountChanged is invoked in the context of the dataGrid; so this is the dataGrid in your callback, or use the same closure describe in B)
B) Use a closure, which works even if multiple grids (displays) are bound to the same dataView (which is only possible because dataView is not associated with a particular Grid).
When you create the grid using the dataView (or assign it later), in the same scope (in which grid is available), subscribe to the callback using a helper function to enclose the grid:
function watchRowCountChanges(grid, dataView) {
dataView.onRowCountChanged.subscribe(function (e, args) {
grid.updateRowCount(); // `grid` is a _local_ variable
grid.render();
console.log(grid.name, this === dataView); // true story, use either!
});
}
// elsewhere...
var grid1 = new Slick.Grid(element1, dataView, columns1, options1);
grid1.name = 'grid1';
watchRowChanges(grid1, dataView);
var grid2 = new Slick.Grid(element2, [], columns2, options2);
grid2.name = 'grid2';
grid2.setData(dataView);
watchRowChanges(grid2, dataView);
And when the row count changes:
grid1 true
grid2 true

Related

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);
}

Kendo UI dataSource changed event: is it working?

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.

jQuery Delegate not binding like I want it to

Using jQuery 1.7
I'm having trouble binding a Click event to some dynamically loaded content.
I've looked around, tried .live, .delegate and .on, and I just can't get it to work.
This is my code:
$(".fileexplorer_folderdlg").delegate(".delete", "click", function () {
console.log("Hello world!");
});
The thing is, .fileexplorer_folderdlg is dynamically loaded. If I use .fileexplorer (not dynamically loaded), it works, but I have more elements with the .delete class that I do not wish to bind to (and neither element classes can be renamed or changed for various reasons).
I also tried using .fileexplorer_folderdlg .delete as the .delegate selector, didnt work either!
Of course I could just add another unique class to the elements I wish to bind to, but this really should work, right?
I believe this would work:
$(document).on('click', '.delete', function() {
if ($(this).closest('.fileexplorer_folderdlg').length) {
console.log('hello, world!');
}
});
or even just:
$(document).on('click', '.fileexplorer_folderdlg .delete', function() {
console.log('hello, world!');
});
As you've found, you can't bind on .fileexplorer_folderdlg because it's dynamic. You therefore need to bind on some static element that will contain that element at some point in the future.
Instead, this binds on the document (but will unfortunately fire for every single click on the document thereafter).
EDIT by Jeff
Although the code above did not work, modifying it a bit did the job, although not the most desirable solution.
$(document).on('click', '.delete', function () {
if($(this).closest(".fileexplorer") != null)
console.log("Thanks for your help!");
});
It works, but this event is fired for all other .delete classes, of which there are many. What I do not understand though, is why using .fileexplorer_folderdlg .delete did not work!

Titanium Mobile: reference UI elements with an ID?

How do you keep track of your UI elements in Titanium? Say you have a window with a TableView that has some Switches (on/off) in it and you'd like to reference the changed switch onchange with a generic event listener. There's the property event.source, but you still don't really know what field of a form was just toggled, you just have a reference to the element. Is there a way to give the element an ID, as you would with a radiobutton in JavaScript?
Up to now, registered each form UI element in a dictionary, and saved all the values at once, looping through the dictionary and getting each object value. But now I'd like to do this onchange, and I can't find any other way to do it than create a specific callback function for each element (which I'd really rather not).
just assign and id to the element... all of these other solution CAN work, but they seem to be over kill for what you are asking for.
// create switch with id
var switcher0 = Ti.Ui.createSwitch({id:"switch1"});
then inside your event listener
myform.addEventListener('click', function(e){
var obj = e.source;
if ( obj.id == "switch1" ) {
// do some magic!!
}
});
A simple solution is to use a framework that helps you keep track of all your elements, which speeds up development quite a bit, as the project and app grows. I've built a framework of my own called Adamantium.js, which lets you use a syntax like jQuery to deal with your elements, based on ID and type selectors. In a coming release, it will also support for something like classes, that can be arbitrarily added or removed from an element, tracking of master/slave relationships and basic filter methods, to help you narrow your query. Most methods are chainable, so building apps with rich interaction is quick and simple.
A quick demo:
// Type selector, selects all switches
$(':Switch')
// Bind a callback to the change event on all switches
// This callback is also inherited by all new switch elements
$(':Switch').bind('change', function (e) {
alert(e.type + ' fired on ' + e.source.id + ', value = ' + e.value);
});
// Select by ID and trigger an event
$('#MyCustomSwitch').trigger('change', {
foo: 'bar'
});
Then there's a lot of other cool methods in the framework, that are all designed to speed up development and modeled after the familiar ways of jQuery, more about that in the original blog post.
I completely understand not wanting to write a listener to each one because that is very time consuming. I had the same problem that you did and solved it like so.
var switches = [];
function createSwitch(i) {
switches[i] = Ti.UI.createSwitch();
switches[i].addEventListener('change', function(e) {
Ti.API.info('switch '+i+' = '+e.value);
});
return switches[i];
}
for(i=0;i<rows.length;i++) {
row = Ti.UI.createTableViewRow();
row.add(createSwitch(i));
}
However keep in mind that this solution may not fit your needs as it did mine. For me it was good because each time I created a switch it added a listener to it dynamically then I could simply get the e.source.parent of the switch to interact with whatever I needed.
module Id just for the hold it's ID. When we have use id the call any another space just use . and use easily.
Try This
var but1 = Ti.Ui.createButton({title : 'Button', id:"1"});
window.addEventListener('click', function(e){
var obj = e.source;
if ( obj.id == "1" ) {
// do some magic!!
}
});
window.add(but1);
I, think this is supported for you.
how do you create your tableview and your switcher? usually i would define a eventListener function while creating the switcher.
// first switch
var switcher0 = Ti.Ui.createSwitch();
switch0.addEventListener('change',function(e){});
myTableViewRow.add(switch0);
myTableView.add(myTableViewRow);
// second switch
var switch1 = ..
so no generic event listener is needed.

Event removal in Mootools, and syntax of event addition

So I have been adding my events thusly:
element.addEvent('click', function() {
alert('foobar');
});
However, when attempting to remove said event, this syntactically identical code (with "add" switched to "remove") does not work.
element.removeEvent('click', function() {
alert('foobar');
});
I assume this is because the two functions defined are not referenced the same, so the event is not technically removed. Alright, so I redefine the event addition and removal:
element.addEvent('click', alert('foobar'));
element.removeEvent('click', alert('foobar'));
Which works great, except now when the page loads, the click event is fired even before it's clicked!
The function is removed, though, which is great......
update: when you do .addEvent('type', function(){ }) and .removeEvent('type', function(){ }), even though the functions may have the same 'signatures', they are two separte anonymous functions, assigned on the fly. function 1 is !== to function 2 - hence there is no match when MooTools tries to remove it.
to be able to remove an exact handler, o:
function handler(){ ... }
el.addEvent('click', handler);
// .. later
el.removeEvent('click', handler);
Internally, events are actually a map of keys to functions in element storage. have a look at this fiddle i did a while back for another SO question - http://www.jsfiddle.net/mVJDr/
it will check to see how many events are stacked up for a particular event type on any given element (or all events).
similarly, removeEvent looks for a match in the events storage - have a look on http://jsfiddle.net/dimitar/wLuY3/1/. hence, using named functions like Nikolaus suggested allows you to remove them easily as it provides a match.
also, you can remove events via element.removeEvents("click") for all click events.
your page now alerts because you pass on alert as the function as well as execute it with the params 'foobar'. METHOD followed by () in javascript means RUN THE METHOD PRECEDING IT IMMEDIATELY, NOT LATER. when you bind functions to events, you pass the reference (the method name) only.
to avoid using an anonymous function and to pass argument,s you can do something like:
document.id('foobar').addEvent('click', alert.bind(this, 'foo'));
as bind raps it for you, but removing this will be even more complicated.
as for event delegation, it's:
parentEl.addEvents({
"click:relay(a.linkout)": function(e, el) {
},
"mouseover:relay(li.menu)": function(e, el) {
}
});
more on that here http://mootools.net/docs/more/Element/Element.Delegation#Element:removeEvent
keep in mind it's not great / very stable. works fine for click stuff, mouseenter is not to be used delegated, just mouseover - which means IE can fire mouseout when it should not. the way i understand it, it's coming improved in mootools 2.0
edit updating to show an example of bound and unbound method within a class pattern in mootools
http://www.jsfiddle.net/wmhgw/
var foo = new Class({
message: "hi",
toElement: function() {
return this.element = new Element("a", {
href: "http://www.google.com",
text: "google",
events: {
"click": this.bar.bind(this), // bind it
"mouseenter": this.bar // unbound -> this.element becomes this
}
});
},
bar: function(event) {
event.stop();
// hi when bound to class instance (this.message will exist)
// 'undefined' otherwise.
console.log(this.message || "undefined");
}
});
document.id(new foo()).inject(document.body);
the mouseenter here will be unbound where this will refer to the default scope (i.e the element that triggered the event - the a href). when bound, you can get the element via event.target instead - the event object is always passed on to the function as a parameter.
btw, this is a slightly less familiar use of class and element relation but it serves my purposes here to illustrate binding in the context of classes.
assig the function to a variable and use the same reference to add and remove the event.
if you use an anonymous function you will get to different references
var test = function(){ alert('test: ' + this.id); }
$('element').addEvent('click', test);
...
$('element').removeEvent('click', test);
addEvent : Attaches an event listener to a DOM element.
Example -
$('myElement').addEvent('click', function(){
alert('clicked!');
});
removeEvent : Works as Element.addEvent, but instead removes the specified event listener.
Example -
var destroy = function(){ alert('Boom: ' + this.id); } // this refers to the Element.
$('myElement').addEvent('click', destroy);
//later...
$('myElement').removeEvent('click', destroy);
This means when you add an event with a eventhandler not an anonymous function if you than remove the event than it will be removed.

Resources