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

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>

Related

Kendo UI - Drop down list Setting Value autoBind = false setting

I am evaluating kendo ui right now to use in our big application. We have a situation where we have much values in dropdowns (like 200+) and there are more than 1 drop down with that size. So if we have a complex form. The Page Load takes time to render the form. (Due to that each box needs to be loaded from service and filled up).
We avoided this by writing our own asp.net web control with on demand support (like autoBind property) in the drop down list in kendo ui.
Now, DropDownList from KendoUI serves the purpose with autobind = false, BUT when setting value it fetches data from remote binding first and then selects appropriate value. (this is cool and really good for small lists) but Potentially this will mean that when we load the page and set the value it will issue remote binding calls for each of the drop downs.
Now,
Can we set value/ text to appear without issuing the remote binding. We want remote binding to be done ONLY when the user clicks on the drop down itself. (not when we are filling form). This will save extra calls to system and help quickly render the form to user.
Here is JS Bin
http://jsbin.com/ayivad/3/edit
If somebody from kendo ui would like me to help out - let me know, but this idea will allow us to use kendo ui drop downs with good use.
<input type="button" id="btnSet" value="Set Value (Click without clicking on DropDown" />
<br/><br/>
<select id="products"></select>
$(document).ready(function () {
$("#products").kendoDropDownList({
dataTextField: "ProductName",
dataValueField: "ProductID",
autoBind: false,
dataSource: {
transport: {
read: {
dataType: "jsonp",
url: "http://demos.kendoui.com/service/Products",
}
}
}
});
var combobox = $("#products").data("kendoDropDownList"),
setValue = function (e) {
if (e.type != "keypress" || kendo.keys.ENTER == e.keyCode)
combobox.value(3);
};
$("#btnSet").click(setValue);
});
Thanks,
Riz
1) Set text instead of value : http://docs.kendoui.com/api/web/dropdownlist#configuration-text
Kendo:
text String(default: "")
Define the text of the widget, when the autoBind is set to false.
Example
$("#dropdownlist").kendoDropDownList({
autoBind: false,
text: "Chai"
});
dirty alternative - Try to hijack ddl "optional label" for your needs. Load your data for the page inclusive of the value you want to show at the ddl, then initialize ddl's with optional values equal to the value you want to show. Once user opens the ddl, remote data will load, once data loaded you will ovewrite/remove the optional label and happy days.
http://docs.kendoui.com/api/web/dropdownlist#configuration-optionLabel
(Consider splitting the list, 200 long drop down us far from user friendly.)
$("#dropdownlist").kendoDropDownList({
optionLabel: "My value" });
Also consider using Kendo ComboBox, afterall auto complete after 3 chars or so sounds as quite sensible solution in case of your 200 items. We use same solution to 500 + combobox.

Loading a hidden div into an AJAX jQuery UI tab (future DOM element)

I have been trying to manipulate content that is loaded into jQuery UI tabs via AJAX.
As you can imagine, these elements are "future" DOM elements and aren't manipulated by normal $(".someClass")functions.
I've read using .live() for event handling is now deprecated using jQuery 1.7+ and is replaced by the new .on() method.
My issue is that the div I want to hide, when it loads in an AJAX tab, must be manipulated after the initial DOM load and is not bound to a click event at first.
My functions, which are currently wrapped in $() are below.
I think I have the syntax correct for links that use a click handler, but I'm not sure of the correct way to ".hide()" my "hiddenStory" div at load.
I also think that the functions themselves shouldn't be wrapped in an overall $()?
Any help or advice would be greatly appreciated.
$(function(){
// this .hiddenStory div below is what I want to hide on AJAX load
// need syntax and/or new methods for writing this function
$(".hiddenStory").hide();
// this is a function that allows me to toggle a "read more/read less" area
// on the "hiddenStory" div
$(".showMoreOrLess").on('click', (function() {
if (this.className.indexOf('clicked') != -1 ) {
$(this).removeClass('clicked');
$(this).prev().slideUp(500);
$(this).html("Read More" + "<span class='moreUiIcon'></span>");
}
else {
$(this).addClass('clicked');
$(this).prev().slideDown(500);
$(this).html("See Less" + "<span class='lessUiIcon'></span>");
}
}));
});
// prevents default link behavior
// on BBQ history stated tab panes with
// "showMoreOrLess" links
$('.showMoreOrLess').click(function (event)
{
event.preventDefault();
// here you can also do all sort of things
});
// /prevents default behavior on "showMoreOrLess" links
Could you set the display: none via CSS and override it when you wanted to show the element's content? Another option, if you have to do it this way would be to add the `$(".hiddenStory").hide() in the callback from the AJAX load that is populating the element. For example:
$(".hiddenStory").load("http://myurl.com", function(){
$(".hiddenStory").hide();
}
);
If you aren't using the .load method, you should have some sort of call back to tie into (e.g. success if using $.ajax...)

ajax replace content lose focus on text box

I don't even know if this is possible but here is an example:
<div id="register">
//bunch of markup including inputs
</div>
Via AJAX I replace the register div, but if there is a focus on a text box inside of the register div, it loses focus when replaces happens. Is there a way to maintain focus?
here is the javascript:
$("#cart_contents input").change(function()
{
$(this.form).ajaxSubmit({target: "#register_container", success: function()
{
}
});
});
I have lots of inputs inside this form, how can I figure out how to refocus
If you get an ID handle for the text box, e.g. textbox, when AJAX is complete, call:
$('#textbox').focus();
A more generic solution. Given focusable elements have IDs, bookend your AJAX stuff like so:
var focusedId = $(document.activeElement).attr('id');
// .. AJAX, replacement ..
$('#' + focusedId).focus();
Reference focus()jQuery, Using jQuery to test if an input has focus.
If you replace the markups inside the register div,the focus from earlier fields would be removed,use
$("#"+someid).focus();
to focus on the textfields with id if you are using jquery..

how to fake a click on a dynamic element?

On a static element, to fake a click, I use
$(selector).click();
But how can I do the same thing on a dynamic element (resulted from an ajax call)?
The same...:
$(selector).click();
Why didn't you try it first?
P.S. it is not called fake a click, it's called trigger the click event.
$(selector).trigger('click'); == $(selector).click();
Update
You need to bind that element a callback to the event in order it to work:
$(selector).click(function(){...});
$(selector).click();
If you want it to have the the click callback you assigned to the static elements automaticlly, you should use on\ delegate (or live but it's deprecated) when you attach the click callback.
$('body').on('click', 'selector', function(){...})
instead if body use the closest static element the holds that selector elements.
See my DEMO
within your ajax success function try your code:
$(selector).click();
Basing this on your previous question : How can I select a list of DOM objects render from an AJAX call?
$(document).ready(function(){
var listItems = $('#myList li a');
var containers = $('#myContainer > div');
listItems.click(function(e){//do someting
});
etc...
If the elements you are trying to attach a click handler to are supposed to be inside any of the two variables above then you WILL have to update those variables after the elements are inserted into the DOM, as it is right now only elements that exists during first page load will be inside those variables.
That is the only reason I can think of why something like :
$(document).on('click', listItems, function(e) {//do something
});
will not work!
Don't know if I understand (I'm french sorry...)
But try :
$(selector).live('click',function(){}); // deprecated it seems
Demo of gdoron with live() : http://jsfiddle.net/Rx2h7/1/
use on() method of jquery,
staticElement.on('click', selector, function(){})
on method generates click event on dynamically created element by attaching it to the static element present in the DOM .
For further reference check this out -- https://api.jquery.com/on/

Add complex markup with event handlers

How to put into a grid cell not just a string <span>text</span>, but a string with an event handler?
This option does not suit me:
<span onclick='function(){...}'>click me</span>
I need to add, for example, such elements in one grid cell:
var $el1 = $('<button>clck me 1</button>').click(function(){...});
var $el2 = $('<button>clck me 2</button>').click(function(){...});
...
I use slick.dataview.
Don't.
Either handle click events via SlickGrid by using the onClick event it exposes or use event delegation on a higher level (container or document) to catch it. Add an attribute to the buttons to distinguish them later and decide which handler to execute.

Resources