Consuming GWT click events - events

Due to performance reasons, I have a custom made table. The table consists of columns that are created as HTML DIVs, and the row is wrapped into an AbsolutePanel. The position of the column(s) and the row(s) is absolute and calculated on the render loop. The table is added into a ScrollPanel and only renders the visible portion of the rows, and adds rows when the user scrolls.
Customer requirement is to open a PopupPanel to show details about the row when the row is clicked. I've added a ClickHandler to the row panel by sinking the click event into it, which works fine.
The problem is, if I add e.g. a standard link or any clickable item into one of the cells in the table, clicking on the said item(s) results in also the row click handler firing, which I want to somehow prevent. The source of the event is the row Element, not the link/icon/whatever that was clicked.
Any help solving this (perhaps a completely different approach ?) is much appreciated.

I would use gwtquery because of its simplicity and performance.
I don't know the final dom renderized by your app, but if we suppose you have something like this:
<div id="column1">
<div id="row1_1" class="my_row" product_id="whatever"> content </div>
...
</div>
Your code could be something like this:
import static com.google.gwt.query.client.GQuery.*;
$(".my_row").click(new Function(){
public void f() {
// The gquery instance of the row clicked
GQuery thisRow = $(this);
// Use gquery methods to get some info of your row
String thisId = thisRow.id();
String productId = thisRow.attr("product_id");
Element thisElement = thisRow.get(0);
// do Something with your row
...
}
});

Related

Hide child grid when adding new main item

I have a grid that has child grid for each item, when i add a new item to the main grid, there is a stub for the child (with the toolbar etc and an empty grid for the child), I would like to hide the child grid when adding new one, i know i need the edit event, i just dont know how to get reference to the detailgrid for the item that the row was just created for input.
edit event has e.sender, e.container, e.model, first 2 reference the main grid of course as the event is raised by the main grid
The required behavior is not supported out of the box, however you can for example attach click event handler to the expanding arrows in the Grid. In the event handler you can prevent the expanding if current model is new. Please check the example below:
//Change Employees with your grid name
//the grid should have model ID defined
$("#Employees table").on("click", ".k-hierarchy-cell a", function (e) {
dataItem = $("#Employees").data("kendoGrid").dataItem($(e.srcElement).closest("tr"));
//check if is new record
if (dataItem.isNew()) {
e.preventDefault();
e.stopImmediatePropagation();
}
})
UPDATE (as requested): The above code should be executed in script tag (wrapped in document "ready" event handler) which is placed just after the Grid initialization code.

Set title and additional properties to kendo ui grid

I am using kendo ui grid to display data. I want to set title for the grid.Is there any way to set it.
Also I want to set some additional/custom property for grid which will help to identify the grid uniquely. Any custom property I can set to grid so I can get its value when required.
So in case if there are more instances on grid this will help.
Please suggest on this.
Iterating through all your tables can be done using:
$.each($(".k-grid"), function (idx, grid) {
// Do whatever you want to do with "grid"
...
});
If you want to add a title, might be something like:
$.each($(".k-grid"), function (idx, grid) {
$(grid).data("kendoGrid").wrapper.prepend('<div class="k-grid-header"><table><thead><tr><th class="k-header">Title</th></tr></thead></table></div>');
});
For setting a click event to the HTML img elements, you can do:
$("tr", ".k-grid").on("click", "img:first", function () {
// Here "this" is the "img" on which you clicked, finding the grid is:
var grid = $(this).closest(".k-grid").data("kendoGrid");
console.log("grid", grid);
// If you want to access the "id"
console.log("id", grid.element.attr("id"));
});
Once you click on the first image of each row what I do in the event handler is finding the closest HTML element with k-grid class (the grid): this is the HTML containing the grid.
If you want to get Kendo UI grid element the you need to use data("kendoGrid").
Simple and elegant.
In this JSFiddle: http://jsfiddle.net/OnaBai/2qpT3/2/, if you click on "Add Titles" button you add a title to each table and if you click on "Add Handlers" and then in an image, you will get an alert with the id of the table that the image belongs to.
EDIT: If you want to iterate on every image that is in the first column, of every KendoUI grid on your document, you should do:
$.each($("td:first > img", ".k-grid table tbody > tr"), function (idx, elem) {
// "elem" is the image
console.log(idx, elem);
// associate event
$(elem).on("click", fnHandler);
});
I prefer to change the title like this:
$("#grid th[data-field=Field]").html("Title");

Two slick grid questions: 1. How to highlight the column header, 2. How to get to know when the end of scroll has happened

I am building a website using slickgrid and I have these two problems:
I want to select the entire column whenever the user clicks on the column header. I have been able to change the style of the cells as given in this example. I have not been able to figure out how to change the style of the column header
How to get to know when the end of scroll has happened in slickgrid. I am currently doing
$(".slick-viewport").scroll(function () {
if ($(this)[0].scrollHeight - $(this).scrollTop() <= $(this).outerHeight()) {
handle_end_of_scroll()
}
})
But I am dependent on the css class name of the slick grid body and I might have issues if I end up updating slickgrid later to a newer version. I might have to update this part of the code if the implementation of slickgrid changes.
Change the style of a header
You could force an update to a header which would trigger a onHeaderCellRendered event in which you could then change the class on the header. Pretty messy, though.
grid.onHeaderCellRendered.subscribe(function (e, args) {
var headerCell = args.node;
});
grid.updateColumnHeader('columnID');
Check if scrolled to end
Binding to scroll events directly is always bad. You should subscribe the the onViewportChanged event and getViewport method to check if you have reached the end.
grid.onViewportChanged.subscribe(function () {
var lastRow = grid.getViewport().bottom;
if (lastRow >= grid.getDataLength() - 1) {
console.log('at bottom');
}
});

How to load a div after the line break on click event?

I'm creating under Wordpress a single page portfolio. Each gallery thumbnail is a list item.
When you click an item, it loads a sliding drawer (#DrawerContainer) pulling the content from the post with ajax.
I want this drawer to appear on the line after the clicked item.
Since it's a fluid layout, I don't know if the browser is displaying 1,2,3,4 or 5 items in a row.
I tried to append my drawer to every <li> but I'm afraid if I click a thumbnail,
the slider will open and make the other thumbnails jump to the next line.
So I thought the best way to prevent layout problems is to call the drawer only after a line break.
How can I target the last li item in the row, and load a div after the line break of this row?
If I'm not clear, here is the code I'd like to see rendered
EDIT: I just added the code to jsfiddle if you want to put your hands on it. http://jsfiddle.net/F6MvZ/10/
<ul id="portfolio-list">
<li>item1</li>
<li>item2</li>
<li>item3</li> //end of first row (br/)
<li>item4</li> //if I click this item
<li>item5</li>
<li>item6</li> //end of second row (br/)
<div id="DrawerContainer"></div> // the content of item4 appears here
<li>item7</li> //end of third row
</ul>
and here is the code I'm struggling with
$(document).ready(function(){
$.ajaxSetup({cache:false});
$(".ProjectWrap,.mosaic-overlay,.mosaic-backdrop").click(function(){
var post_link = $(this).attr("href");
//$('#DrawerContainer').slideToggle(500);
$("#DrawerContainer").html("loading...");
$("#DrawerContainer").load(post_link + " #container > * ");
return false;
});
//Here is the part I'm stuck with now
$(#portfolio-list).click(function(){
$("<br/>").append('<section id="DrawerContainer"></section>');
});
//I assume the #DrawerContainer will generate a br/
});
Looking for something like this?
http://jsfiddle.net/RF6df/1/
Its an extension of what I originally wrote. Hope this helps.

Browser Memory Usage Comparison: inline onClick vs. using JQuery .bind()

I have ~400 elements on a page that have click events tied to them (4 different types of buttons with 100 instances of each, each type's click events performing the same function but with different parameters).
I need to minimize any impacts on performance that this may have. What kind of performance hit am I taking (memory etc) by binding click events to each of these individually (using JQuery's bind())? Would it be more efficient to have an inline onclick calling the function on each button instead?
Edit for clarification :):
I actually have a table (generated using JQGrid) and each row has data columns followed by 4 icon 'button' columns- delete & three other business functions that make AJAX calls back to the server:
|id|description|__more data_|_X__|_+__|____|____|
-------------------------------------------------
| 1|___data____|____data____|icon|icon|icon|icon|
| 2|___data____|____data____|icon|icon|icon|icon|
| 3|___data____|____data____|icon|icon|icon|icon|
| 4|___data____|____data____|icon|icon|icon|icon|
I am using JQGrid's custom formatter (http://www.trirand.com/jqgridwsiki/doku.php?id=wiki:custom_formatter) to build the icon 'buttons' in each row (I cannot retrieve button HTML from server).
It is here in my custom formatter function that I can easily just build the icon HTML and code in an inline onclick calling the appropriate functions with the appropriate parameters (data from other columns in that row). I use the data in the row columns as parameters for my functions.
function removeFormatter(cellvalue, options, rowObject) {
return "<img src='img/favoritesAdd.gif' onclick='remove(\"" + options.rowId + "\")' title='Remove' style='cursor:pointer' />";
}
So, I can think of two options:
1) inline onclick as I explained above
--or--
2) delegate() (as mentioned in below answers (thank you so much!))
Build the icon image (each icon type has its own class name) using the custom formatter.Set the icon's data() to its parameters in the afterInsertRow JQGrid event. Apply the delegate() handler to buttons of specific classes (as #KenRedler said below)
> $('#container').delegate('.your_buttons','click',function(e){
> e.preventDefault();
> var your_param = $(this).data('something'); // store your params in data, perhaps
> do_something_with( your_param );
> }); //(code snippet via #KenRedler)
I'm not sure how browser-intensive option #2 is I guess...but I do like keeping the Javascript away from my DOM elements :)
Because you need not only a general solution with some container objects, but the solution for jqGrid I can suggest you one more way.
The problem is that jqGrid make already some onClick bindings. So you will not spend more resources if you just use existing in jqGrid event handler. Two event handler can be useful for you: onCellSelect and beforeSelectRow. To have mostly close behavior to what you currently have I suggest you to use beforeSelectRow event. It's advantage is that if the user will click on one from your custom buttons the row selection can stay unchanged. With the onCellSelect the row will be first selected and then the onCellSelect event handler called.
You can define the columns with buttons like following
{ name: 'add', width: 18, sortable: false, search: false,
formatter:function(){
return "<span class='ui-icon ui-icon-plus'></span>"
}}
In the code above I do use custom formatter of jqGrid, but without any event binding. The code of
beforeSelectRow: function (rowid, e) {
var iCol = $.jgrid.getCellIndex(e.target);
if (iCol >= firstButtonColumnIndex) {
alert("rowid="+rowid+"\nButton name: "+buttonNames[iCol]);
}
// prevent row selection if one click on the button
return (iCol >= firstButtonColumnIndex)? false: true;
}
where firstButtonColumnIndex = 8 and buttonNames = {8:'Add',9:'Edit',10:'Remove',11:'Details'}. In your code you can replace the alert to the corresponding function call.
If you want select the row always on the button click you can simplify the code till the following
onCellSelect: function (rowid,iCol/*,cellcontent,e*/) {
if (iCol >= firstButtonColumnIndex) {
alert("rowid="+rowid+"\nButton name: "+buttonNames[iCol]);
}
}
In the way you use one existing click event handler bound to the whole table (see the source code) and just say jqGrid which handle you want to use.
I recommend you additionally always use gridview:true which speed up the building of jqGrid, but which can not be used if you use afterInsertRow function which you considered to use as an option.
You can see the demo here.
UPDATED: One more option which you have is to use formatter:'actions' see the demo prepared for the answer. If you look at the code of the 'actions' formatter is work mostly like your current code if you look at it from the event binding side.
UPDATED 2: The updated version of the code you can see here.
You should use the .delegate() method to bind a single click handler for all elements ,through jQuery, to a parent element of all buttons.
For the different parameters you could use data- attributes to each element, and retrieve them with the .data() method.
Have you considered using delegate()? You'd have one handler on a container element rather than hundreds. Something like this:
$('#container').delegate('.your_buttons','click',function(e){
e.preventDefault();
var your_param = $(this).data('something'); // store your params in data, perhaps
do_something_with( your_param );
});
Assuming a general layout like this:
<div id="container">
<!--- stuff here --->
<a class="your_buttons" href="#" data-something="foo">Alpha</a>
<a class="your_buttons" href="#" data-something="bar">Beta</a>
<a class="your_buttons" href="#" data-something="baz">Gamma</a>
<a class="something-else" href="#" data-something="baz">Omega</a>
<!--- hundreds more --->
</div>

Resources