I've written some javascript using jQuery to replace any select lists with a div and ul alternative so that it will give me some more styling control and make the drop downs look the same cross browser. The below code works 99% for me but I have one issue. At the bottom of the code I have had to use .delay() to tell the code in a way to wait for the .each() loop above to finish doing what its doing. The problem with this is that there is atleast one second untill the replacement happens leaving a flash of the old select boxes. Also I can forsee another problem is what if it takes more than one second for the each() loop to complete...
How can I get the code at the bottom to only run once the each loop has run and complete. Also I welcome any optimizations on the rest of the code.
EDIT: Some of the HTML has been stripped from the code so I have pastebinned it: http://pastebin.com/4HFLjHE1
// Check when ready
$(function() {
// Find dropdowns
$("select.dropdownreplace").each(function() {replaceDropDown(this);});
// If document clicked anywhere hide drop downs
$(document).click(function(event){
$("div.dropdownreplace ul").hide();
});
});
function replaceDropDown(that) {
// Create HTML for new drop down
// hidden field
var hiddeninput = $('');
// div
var dropdowndiv = $(''+$(":selected", that).text()+'');
// loop through values and make li's
$("option", that).each(function() {
$("ul", dropdowndiv).append(''+$(this).val()+''+$(this).text()+'');
// set click handler for this drop down
$(dropdowndiv).click(function() {
$("ul", this).show();
return false;
});
// set click handler for link items
$("a", dropdowndiv).click(function() {
// Get name of hidden input
var nameofdropdown = $(this).parent().parent().parent().attr('id');
var nameofinput = nameofdropdown.replace("dropdownreplacement_", "");
// set hidden input value to whats been clicked
$("[name='"+nameofinput+"']").val($(this).parent().find("span").text());
// set div
$("div#"+nameofdropdown+" > span").text($(this).text());
$("div#"+nameofdropdown+" ul").hide();
return false;
});
});
// Remove drop down then add in replacement html
$(that).delay(1000).after(hiddeninput);
$(that).delay(1100).after(dropdowndiv);
$(that).delay(1200).remove();
}
Thnaks
Scott
Inside your function, compare the index jquery passes you, with the total number of items you have.
I don't know your html, but I believe you can do this.
Change your function so it receives the index param that jquery sends.
$("option", that).each(function(index) {
Then, at the end of that function compare the length with the index, if they are the same, then you're done
if ( $('option', that).length == (index +1 ) ) {
$(that).after(hiddeninput);
$(that).after(dropdowndiv);
$(that).remove();
}
From my tests, this should be what you need. Don't know if there is a more "standard" way to do it.
Hope this helps
What you have to do is create a callback functionl. In your each(), after the initial function you can indicate it has to do some more things when it's finished:
$("option", that).each(function() {
<...code...>
}, function() {
<...code...> //this gets performed after the previous function is complete
});
Related
I hit a problem with the onclick function when i add divs with ids like "n_block"+(1-~). When I use the jquery zoom function on the objects to make them smaller or bigger onClick doesn't work anymore. I'm not really good at programming so the code might be kind of confusing.
Heres the code i use for the onClick of items:
$(document).on("click",function (e, ui){
//When the document gets clicked, check if one of the items was clicked.
if($(e.target).is($("#n_block" + cloneCount1)) || $(e.target).is($("#n_block" + cloneCount1+ " span"))){
//Set current item.
var item = $("#n_block" + cloneCount1);
//Set style to current item.
item.css("border-color", "Black");
item.css("border-width","2px");
item.css("background-color", "floralwhite");
jsPlumb.repaintEverything();
//Check if key Delete was pressed while item selected & delete that item with his children.
$('html').keydown(function(e){
if(item.css("border-width")=="2px"){
if(e.keyCode == 46) {
/* Prevents line bugging*/
jsPlumb.detachEveryConnection();
jsPlumb.deleteEveryEndpoint();
var razred = getClass(item, "b_"),
id = item.prop("id");
item.remove();
if(razred == "b_2"){
$(".ovoj."+id).remove();
}
else if (razred == "b_4"){
$(".ovojLoop."+id).remove();
$(".empty_block_c."+id).remove();
}
if ( $('.objects').find('div').length == 2) {
$(".objects").empty();
$(".objects").append('<div class="b_s" id="start_block">START</div><p id="start_text">Insert symbols here!</p><div class="b_s" id="end_block">STOP</div> ');
}else{
/* Connects objects together with line. ****/
povezi(cloneCount, tip_crte, ".objects");
}
}
jsPlumb.repaintEverything();
}
});
}
// If item is not clicked set this css to the current item.
else{
$("#n_block" + cloneCount1).css("border-width","1px");
jsPlumb.repaintEverything();
}
});
And heres the zoom code for zooming in when button is clicked:
var currentZoom = 1.0;
$(".zoomin").click(function (){
//Detaches the connections from item to item.
jsPlumb.detachEveryConnection();
jsPlumb.deleteEveryEndpoint();
//Prevents spamming of button, animates the objects
$(".project").stop().animate({ "zoom": currentZoom += .1}, "slow", function() {
if(!$(".objects").children().is($("p"))){
povezi(cloneCount, tip_crte, ".objects");
}
});
});
Use event delegation for binding events to dynamically added elements.
$(document).on('click', ".zoomin", function (){
//Your code.
});
When you use normal .click() to bind event to an element, then that even gets bound to only those elements which exist in the DOM at the moment of the execution of code. Using event delegation, you can tell jQuery that we need to add the handler to every '.zoomin' element which comes inside a particular element no matter when it is added.
The solution depends when exactly is the script which tries to bind the events are executed.
For Eg: Lets assume this script is in document ready function of jquery
$(document).ready(function(){
$(".zoomin").click(function (){
//your logic here
});
});
Here this script is executed when the page HTML is completed loading into the browser. Now when the script executes it tries to find a element with the class zoomin and if found it will add a event to that element and move on. If the element is not found the script just moves on. So we should actually take care of when the script is executed and is the intended element available at that particular instant of time. If the element is not yet available in the HTML (element might come in later dynamically using jquery) we have 2 options to bind event to the element.
1) Execute the script when the element is being added into the HTML: Lets say I have a event which brings up a pop up with some image. Now I want to zoomin and zoomout the image. Since the image in the popup is added dynamically and I have control of when its being added, I can do this.
$(document).ready(function(){
$('.ViewImage').on('click',function(){
// some code is executed which brings up the popup
// now we know that the image is added into html we can now run the script
$(".zoomin").click(function (){
//your logic here
});
});
});
2) We have no Clue/ Control when the element is added into HTML but still want to bind a event to it: This is scenario where we have no control on when the element is being added or not sure where it is being added from (might be from some external plugin used etc) or not having control at all on the element which is added. Thats when we use this syntax as suggested by #Rejith R Krishnan
$(document).on('click', ".zoomin", function (){
//Your code.
});
This will work on all the elements which are in the HTML at the time of execution of the script and on the elements which will be added in the future with the class name zoomin. So this script can be placed inside/ outside of jquery document ready event
I've got a table with different columns identified with different classes.
I've also a checkbox binded to every column.
I created a function which is called on the click of any checkbox. In this function I hide/show the column which is linked to this.
It doesn't have any javascript error, and the code is the following:
$(document).ready(function(){
$('ul input').click(function(){
//alert('yooo');
if ($(this).is(':checked')) {
//alert('checked');
$("td."+replaceAll(" ","_",$(this).val())).show();
$("th."+replaceAll(" ","_",$(this).val())).show();
//alert($("td").length);
}
else{
//alert('unselected');
$("td."+replaceAll(" ","_",$(this).val())).hide();
$("th."+replaceAll(" ","_",$(this).val())).hide();
}
});
});
However, after every click, the action has a lag (after many clicks it becomes tooooooo slow, many seconds).
I tried also with .css instead of hide-show, but it doesn't make any change.
I understood that the problem was linked only to checkbox, not on callback or on jquery function. I solved the problem simply by working with radio input, adding a "true" and a "false" radio input for every checkbox that was in the page.
Instead of running the jQuery selector on every click like below:
$("td."+replaceAll(" ","_",$(this).val()))
You could set up some sort of caching like:
var cache = {} //<-- declare this outside your click handler
//add the code below inside your click handler
className = replaceAll(" ","_",$(this).val())
if(!cache[className])
cache[className ] = $("td."+className + ", th."+className); //select all the elements once and store in the cache object
$el = cache[className];
if ($(this).is(':checked'))
$el.show();
else
$el.hide();
I am new to jQuery, i want to get the list of last div ID's minimum last three iD's.
my need is when user clicks on cancel button then i want to move user to last 2nd clicked div.
Try this:
var clicks = [];
$("div[id^=test]").on('click',function() {
clicks.push(this.id);
});
$("button").on('click',function() {
console.log(clicks.pop())
});
This uses a array to store all the clicks and the show & removes the last one on button click.
To read about .push() and .pop().
Demo here
Make an "history" array that push the id everytime the div is clicked :
var history = [];
$('div').click(function(){
history.unshift(this.id);
})
And on cancel click:
$('button.cancel').click(function(){
history.shift();
})
To save previous clicks you'll want to store clicks in an array as follows:
clicks = [];
$(function () {
$("div").on("click", function (e) {
// The following is what you wanted, but the uncommented code is better (as it saves future DOM lookups)
// clicks.shift($(this).attr("id"));
clicks.shift(this);
// If you want to use jQuery on the objects, you'll need to call jQuery on them ex: $(this)
// If you do want to remove previous elements, uncomment the following code
// if(clicks.length > 3){
// clicks.pop();
// }
});
});
Each time a click occurs, the object that was clicked on will be stored in the array (clicks.push(this)). Later you can reference the array. clicks[0] will have the most recent click, clicks[1] the next most recent, and so on.
So, to do what you described, you would make a function along the lines of:
$(function () {
$("#cancel").on("click", function (e) {
$(clicks[1]).yourMethods();
});
});
Our web application uses jqGrid for data entry, and data is edited inline and in rows.
A customer wishes a more "Excel-like" experience so that when switching a row to inline editing by clicking on a cell, that cell receives the focus (currently, the first cell in the row gets the focus).
I ran into the same issue. Very frustrating. I modified the jquery.jqGrid.js file to accommodate setting focus on the cell clicked on.
In my editRow function I added the following code:
function editRow(id, row, col, z)
{
grid.jqGrid("editRow", id, true, function ()
{
var f = $("input, select", z.target).focus();
return f;
});
}
This will create a variable f that will ultimately be passed to the "oneditfunc" in $.jgrid.extend
The problem is in the setTimeout function.
$("td:eq("+focus+") input",ind).focus();
as this gets executed with focus set to the first editable field from the .each function above. This would be a great place to pass in a focus index, but not possible.
// End compatible
return this.each(function ()
{
var $t = this, nm, tmp, editable, cnt = 0, focus = null, svr = {}, ind, cm, bfer;
...
I then added the following code. (The line with >>> is unchanged. It is only there to help you find the insertion point in the code.)
>>> $($t).triggerHandler("jqGridInlineEditRow", [rowid, o]);
if ($.isFunction(o.oneditfunc))
{
// modified to allow for setting focus on the
// field clicked on
// sets a return value. this was added to the original code. if using
// legacy code, should see no change as r will be undefined
var r = o.oneditfunc.call($t, rowid);
// if get a return value, this indicates you want to set focus
if (r && r[0])
{
var focusIndex = focus;
var i = 0;
// look for the field name that was clicked on
// cm, which is built above, has no index value associated
// with it, so we must keep track of
var focusField = $.grep(cm, function(c)
{
// find the field name which was clicked on
if (c.name == r[0].name)
focusIndex = i;
i++;
return c.name == r[0].name;
});
// if the field is editable, then update focus index
// which is defined above
if (focusField[0].editable)
{
focus = focusIndex;
}
}
}
The most elegant solution? Probably not, but it does allow all legacy code to work and figure out which field was clicked on so can set focus
Unfortunately the grid can only set focus to the first editable field in the row. You can see this in the source code of grid.inlinedit.js. Here it figures out the index of the row to set focus to, by iterating over them and finding the first one:
if(cm[i].editable===true) {
if(focus===null) { focus = i; }
and later on it sets focus:
$("td:eq("+focus+") input",ind).focus();
Which selects the element at the index stored in the focus variable - for reference, see the :eq selector docs.
That said, if you are so inclined you could edit this section of code to add your own custom logic to control which element receives focus...
I agree with Justin that jqGrid has no direct support of the behavior which you need. The way ich which you can receive which is need can be more complex as just one option of jqGrid. Look at the code from the answer. I hope it will help you.
This is serious deficiency in jqGrid.
If grid is wider than window, you also need to scroll right to make clicked cell visible. For this you can use code from
http://www.trirand.com/blog/?page_id=393/help/inline-edit-problem-with-scrolling/
if (rowID && rowID !== lastSelectedRow) {
var scrollPosition = 0;
scrollPosition = grid2.closest(".ui-jqgrid-bdiv").scrollLeft();
grid2.jqGrid('restoreRow', lastSelectedRow);
grid.jqGrid('editRow', rowID, true);
lastSelectedRow = rowID;
setTimeout(function(){
grid2.closest(".ui-jqgrid-bdiv").scrollLeft(scrollPosition);
},100);
For my part, i used both Justin Ethier and Steve's answers to come up with my own solution (for jqGrid 4.4.3):
In the source of jqGrid, i just comment out the following line (this is to prevent the first input of the edited row to receive the focus):
// commented out
// $("td:eq("+focus+") input",ind).focus();
Then, I create a global js variable that will hold the source of the click on the grid:
var clickedCell;
And finally, set that variable when clicking on the cell.
$('#myJqGrid td').on('click', function(e){ clickedCell = this; });
In order to be able to attach the event to the table cell though, we need to be sure the grid has been created, so it has to be done in the "gridComplete" function of the jqGrid, e.g.:
$('#myJqGrid').jqGrid('setGridParam', {
gridComplete: function(id){
$('#myJqGrid td').on('click', function(e){ clickedCell = this; });
}
});
And finally, when editing the row, i retrieve the clicked cell (saved in the variable "clickedCell"), and give the focus to the input or textarea inside it. This has to be done in the "onSelectRow" function of the jqGrid:
$('#myJqGrid').jqGrid('setGridParam',
{
onSelectRow : function(id) {
...
//switching the selected row to editmode
$('#myJqGrid').jqGrid(
'editRow',
id,
{
keys: true,
// when editing the row, give the focus to the input
//or textarea within the last clicked cell
oneditfunc: function() {
$('input, textarea', clickedCell).focus();
}
);
...
}
}
});
The only problem is there really isn't a solution without touching even slightly the source code of jqGrid. If you don't, it will still work, but the first input will still get the focus at first, shifting the horizontal scroll of your page, even after the correct focus has been assigned.
I posted this answer in another stackoverflow related question. Hope this will apply to you.
I somehow succeeded to accomplish this by attaching a dblclick event to every td of the table, I know this is not the best method, but you are free to optimize it how you like, you can also ignore the setTimeout which was used only for testing.
$("#jqGrid").on("dblclick", "td", function (event) {
// setTimeout(function () {
console.log(this);
$(event.target).find("input,select").focus();
// }, 0);
});
Hope this will help you.
I have a ul with multiple list items and am using jQuery to:
Count the number of list items
Output that value to a different div
Change the color of the output text if that value is greater than 13
In a different div, I have multiple buttons with the class .add or .delete. Not surprisingly, clicking these buttons adds or deletes list items.
The jQuery function works perfectly when the page is loaded, but what I'd like to also do is have this count update every time one of the above buttons is clicked.
Here's my existing code:
var totalItems = $('ul#myList li').length;
$('#outputText').text(totalItems);
if (totalItems > 13) {
$('#outputText').css('color','#F0402B');
};
What do I need to add to make this work? I did look at the answers for this similar question (Run code once on page load, then every time a button is clicked) but they didn't seem to help. Any help would be greatly appreciated!
Apologies if I'm missing something, but basically: Just wrap the code up in a function, call that function on page load, and also call the function after processing the clicks on the buttons.
E.g.:
// The function
function updateTotalItems() {
var totalItems = $('ul#myList li').length;
$('#outputText').text(totalItems);
if (totalItems > 13) {
$('#outputText').css('color','#F0402B');
};
}
// Call on page load
$(updateTotalItems);
// Presumably you're setting up click handlers
$(".add, .delete").click(function() {
// Process the add or delete action
// Update the total
updateTotalItems();
});
//Keep this function outside of document ready to avoid anonymous function.
function updateDiv(){
var totalItems = $('ul#myList li').length;
$('#outputText').text(totalItems);
if (totalItems > 13)
{
$('#outputText').css('color','#F0402B');
}
}
$(document).ready(function() {
// do stuff when DOM is ready
updateDiv();
$('.delete').click(updateDiv());
$('.add').click(updateDiv());
});