I'm using jQuery 1.7.1 and jQueryUI 1.9.1.
I have a spinner, and every time it changes, a text field will be created or removed to match the number on the spinner. Holding the button will cause the number to change very rapidly, causing a ton of fields to be created or removed.
Not a huge problem since it's client-side, but I just don't like it. So I want to disable the rapid spinning when the user holds the spinner buttons.
I came up with a solution using a function for incremental, which looks like this:
var incrementalFunction = function(numOfSpins) {
if (numOfSpins == 1) {
return 1;
}
return 0;
};
This worked great at first, but caused another issue. Next to each newly created text box, I made a 'remove' button that would remove the element and decrement the spinner. But when I call the stepDown method, for some reason, this calls my incremental function, with an increasing numOfSpins every time it was called. So it would only decrement once.
Anyone have a more straightforward solution to preventing the user from holding the increment/decrement buttons (or the up/down arrows on the keyboard)?
If you upgrade to jQuery UI 1.10, the problem will go away. See https://github.com/jquery/jquery-ui/commit/0d53fbfd0b7651652601b3b8577225ab753aab44 which causes stepUp() and stepdDown() to behave as you'd expect.
If you use the stop event, instead of targeting each increment, you can detect when a selection has been made. Then, you can compare that number to how many are currently there, and determine what to do - remove or add more. Try this:
var targetArea = $("#target_area");
targetArea.on("click", ".remover", function () {
$(this).closest("div").remove();
$("#input1").spinner("stepDown");
});
$("#input1").spinner({
stop: function (event, ui) {
var $this = $(this);
var num = $this.val();
var newTargets = targetArea.find("div");
var difference = num - newTargets.length;
if (difference < 0) {
newTargets.slice(difference).remove();
} else if (difference > 0) {
for (var i = 0; i < difference; i++) {
var newTarget = $("<div><input type='text' /><span class='remover' title='Remove'>×</span></div>");
targetArea.append(newTarget);
}
}
}
});
DEMO: http://jsfiddle.net/PJpUC/1/
Related
I am currently working on a postIt for my website where pressing the plus button would create an editable post it/sticky notes. I am done with that part now but I am struggling with the next part which is limiting the number of sticky notes to just 4. I tried having a global variable that would serve as a counter so when the counter is 3, it should stop creating more sticky notes but unfortunately, it is not working.
Here is the link to my workable code:
Sticky note
And this is my futile attempt at limiting the number of sticky notes to 4.
$("#create").click(function(){
var count = 0;
if( count < 4){
$("#create").click(function() {
$(this).before("<textarea></textarea>");
});
count++;
}
}
Can anyone please give me pointers as to how to limit the notes to 4? I have been working on this forever now.
Just move var count = 0; outside the event listener and remove the inner event listener:
var count = 0; // outside the scope of the event listener function bellow so it won't get destroyed/recreated each time the function get called (ie when a clicks happen)
$("#create").click(function() {
if(count < 4) { // we haven't yet exceeded the limits
$(this).before("<textarea></textarea>"); // don't attach another click event listener on #create (we are already in one) so just create the note.
count++;
}
});
Everytime you click create, count the number of textarea elements then determine if you should create a new one:
$("#create").click(function() {
var count = $("textarea");
if (count.length < 4) {
$(this).before("<textarea></textarea>");
}
});
You can even add a class in the newly created textarea to ensure that you only count the ones created by this function.
HTML:
<textarea>This is not part of the group.</textarea>
<textarea class="sticky">This is a sticky note you can type and edit.</textarea>
<div id="create">+</div>
JS:
$("#create").click(function() {
var count = $("textarea.sticky");
if (count.length < 4) {
$(this).before("<textarea class='sticky'></textarea>");
}
});
The problem is that you are defining your count variable inside of your click event handler. As such, every time you click the element, the counter gets reset. You also shouldn't make use of a secondary click handler inside the main one.
To resolve this, bring the count variable outside of the click handler:
var count = 0;
$("#create").click(function() {
if (count < 3) {
$(this).before("<textarea></textarea>");
count++;
}
});
Note that the conditional should check that the count is less than 3, because it increases the count after creation. If it is set to check if the count is less than 4, five notes would be created.
In order to also hide the + after creating the fourth element, you would use:
if (count == 3) {
$(this).hide();
}
After increasing the count.
This can be seen working here.
Hope this helps! :)
I'm puzzled by the function of my JavaScript image slider since it changes the slide only once upon clicking next (I haven't worked on previous yet, but should be logical enough to re-adjust). The code is given by:
$(".room_mdts").click(function(event){
//get the target
var target = event.currentTarget;
var room = $(target).data("room");
currentIndex = parseInt($(target).attr('data-room'));
//First way, by reuse target (only inside this function)
$('#room_details_holder').show();
//The second, by using selectors
//remove all "selected" classes to all which have both "room" and "selected" classes
$('.room_exp.selected').removeClass("selected");
//add "selected" class to the current room (the selector can also be the target variable)
$('.room_exp[data-room='+room+']').addClass("selected");
});
var currentIndex = 0;
var adjIndex = currentIndex - 1,
items = $('.room_details .room_exp'),
itemAmt = items.length;
function cycleItems() {
var item = $('.room_details .room_exp').eq(currentIndex);
items.hide();
item.css('display','inline-block');
}
$('.room_next').click(function() {
adjIndex += 1;
if (adjIndex > itemAmt - 1) {
adjIndex = 0;
}
cycleItems(adjIndex);
cycleItems(currentIndex);
$('#room_name').text($('.room_exp:nth-child('+(adjIndex+2)+')').attr('title'));
});
$('.room_previous').click(function() {
currentIndex -= 1;
if (currentIndex < 0) {
currentIndex = itemAmt - 1;
}
cycleItems(currentIndex);
$('#room_name').text($('.room_exp:nth-child('+(currentIndex+1)+')').attr('title'));
});
$('#room_name').text($('[style*="inline-block"].room_exp').attr('title'));
});
The reason I had to introduce adjIndex is because without '-1' the slide changed by 2 on the first click, again, no idea why.
The Fiddle: https://jsfiddle.net/80em4drd/2/
Any ideas how to fix that it only changes once? (And also, the #room_name only shows after the click, does not show upon expanding).
Try this I rearranged your code a little bit:
made your currentIndex global and assigned with the adjIndex. If that's ok I will improve my answer:
If you click on the right arrow it goes to the end and comes back to the beginning.
url: https://jsfiddle.net/eugensunic/80em4drd/3
code:
function cycleItems() {
currentIndex=adjIndex;
var item = $('.room_details .room_exp').eq(currentIndex);
items.hide();
item.css('display','inline-block');
}
Okay, great thanks to eugen sunic for the little push that got me thinking!
I have finially cracked all of the pieces, although, I might have some extra unecessary bits of code, duplicates etc, but the functionallity is just perfect!
What I have edited:
I moved one of the closing brackets for the cycleFunction () closing bracket to the end of .click functions, that is to make the variable global (at least for those 3 functions)
I changed the title writing function from: $('#room_name').text($('[style*="inline-block"].room_exp').attr('title'));
to:$('#room_name').text($('.room_exp:nth-child('+(adjIndex+2)+')').attr('title'));
Added a few changes regarding .addClass/.removeClass to the $('.room_details_close').click(function(){.
Now, openning any of the thumbnails shows the title immediately (the right title), clicking '<<' or '>>' changes the slide to next and previous, respectively, while the title changes accordingly. Closing the expanded menu and clicking on a different thumbnail results in re-writing the currentIndex (hence, adjIndex too), so the function starts again with no problem.
Please feel free to use!
The new fiddle is: Fiddle
I've created a script that attaches an event listener to a collection of pictures by default. When the elements are clicked, the listener swaps out for another event that changes the image source and pushes the id of the element to an array, and that reverses if you click on the swapped image (the source changes back and the last element in the array is removed). There is a button to "clear" all of the images by setting the default source and resetting the event listener, but it doesn't fire reliably and sometimes fires with a delay, causing only the last element in a series to be collected.
TL;DR: An event fires very unreliably for no discernible reason, and I'd love to know why this is happening and how I should fix it. The JSFiddle and published version are available below.
I've uploaded the current version here, and you can trip the error by selecting multiple tables, pressing "Cancel", and selecting those buttons again. Normally the error starts on the second or third pass.
I've also got a fiddle.
The layout will be a bit wacky on desktops and laptops since it was designed for phone screens, but you'll be able to see the issue and inspect the code so that shouldn't be a problem.
Code blocks:
Unset all the selected tables:
function tableClear() {
//alert(document.getElementsByClassName('eatPlace')[tableResEnum].src);
//numResTables = document.getElementsByClassName('eatPlace').src.length;
tableArrayLength = tableArray.length - 1;
for (tableResEnum = 0; tableResEnum <= tableArrayLength; tableResEnum += 1) {
tableSrces = tableArray[tableResEnum].src;
//alert(tableSrcTapped);
if (tableSrces === tableSrcTapped) {
tableArray[tableResEnum].removeEventListener('click', tableUntap);
tableArray[tableResEnum].addEventListener('click', tableTap);
tableArray[tableResEnum].src = window.location + 'resources/tableBase.svg';
} /*else if () {
}*/
}
resTableArray.splice(0, resTableArray.length);
}
Set/Unset a particular table:
tableUntap = function () {
$(this).unbind('click', tableUntap);
$(this).bind('click', tableTap);
this.setAttribute('src', 'resources/tableBase.svg');
resTableArray.shift(this);
};
tableTap = function () {
$(this).unbind('click', tableTap);
$(this).bind('click', tableUntap);
this.setAttribute('src', 'resources/tableTapped.svg');
resTableArray.push($(this).attr('id'));
};
Convert the elements within the 'eatPlace' class to an array:
$('.eatPlace').bind('click', tableTap);
tableList = document.getElementsByClassName('eatPlace');
tableArray = Array.prototype.slice.call(tableList);
Table instantiation:
for (tableEnum = 1; tableEnum <= tableNum; tableEnum += 1) {
tableImg = document.createElement('IMG');
tableImg.setAttribute('src', 'resources/tableBase.svg');
tableImg.setAttribute('id', 'table' + tableEnum);
tableImg.setAttribute('class', 'eatPlace');
tableImg.setAttribute('width', '15%');
tableImg.setAttribute('height', '15%');
$('#tableBox').append(tableImg, tableEnum);
if (tableEnum % 4 === 0) {
$('#tableBox').append("\n");
}
if (tableEnum === tableNum) {
$('#tableBox').append("<div id='subbles' class='ajaxButton'>Next</div>");
$('#tableBox').append("<div id='cazzles' class='ajaxButton'>Cancel</div>");
}
}
First mistake is in tapping and untapping tables.
When you push a Table to your array, your pushing its ID.
resTableArray.push($(this).attr('id'));
It will add id's of elements, depending on the order of user clicking the tables.
While untapping its always removing the first table.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/shift
resTableArray.shift(this);
So, when user clicks tables 1, 2, 3. And unclicks 3, the shift will remove table 1.
Lets fix this by removing untapped table
tableUntap = function () {
$(this).unbind('click', tableUntap);
$(this).bind('click', tableTap);
this.setAttribute('src', 'http://imgur.com/a7J8OJ5.png');
var elementID = $(this).attr('id');
var elementIndex = resTableArray.indexOf(elementID);
resTableArray.splice(elementIndex, 1);
};
So you were missing some tables after untapping.
Well lets fix tableClear,
You have a array with tapped tables, but you are searching in main array.
function tableClear() {
tableLen = resTableArray.length;
for (var i = 0; i < tableLen; i++) {
var idString = "#" + resTableArray[i];
var $element = $(idString);
$element.unbind('click', tableUntap);
$element.bind('click', tableTap);
$element.attr("src", 'http://imgur.com/a7J8OJ5.png');
}
resTableArray = [];
}
Im searching only tapped tables, and then just untap them and remove handlers.
fiddle: http://jsfiddle.net/r9ewnxzs/
Your mistake was to wrongly remove at untapping elements.
Strange one, not sure if other code in my application is causing this issue, but here goes.
When I fill a grid with data for the first time, it allows me to use the filters straight away. When I click on my reset button (with text in the filters) to clear the grid and prepare it for the next load, the filters do not work straight away, it seems I have to wait about 5 seconds before the filters will adjust the data. Here's my code, bear in mind, this code runs for both reset button and a search button, meaning that in some scenarios it may run twice before the grid being filled with new data.
Reset Code (called in service):
clearAll: function (ref) {
var gridObj = dhtmlxObjectArray[ref];
if(gridObj){
gridObj.clearAll();
if (gridObj.hdr.rows[1].cells[0].getElementsByTagName("INPUT")[0]) {
gridObj.hdr.rows[1].cells[0].getElementsByTagName("INPUT")[0].checked = 0;
}
$rootScope.$broadcast("cvsGridService_toggleExport_" + ref, true);
for (var i = 0; i < gridObj.getColumnsNum(); i++) {
if (gridObj.getFilterElement(i) != null) {
var filterObj = gridObj.getFilterElement(i);
filterObj.value = "";
}
}
$scope.$evalAsync();
}
$rootScope.$broadcast("cvsGridService_updateGridCount_" + ref);
$rootScope.$broadcast("cvsGridService_updateFilteredCount_" + ref, 0);
}
The for loop is where the filters get set to blank. So I wonder if it has anything to so with that? Any other ideas?
Maybe you aren't clearing the filters properly? This is how I do it and it works fine:
for (var i=0; i<grid.filters.length; i++){
grid.filters[i][0].value="";
grid.filters[i][0].old_value="";
}
grid.filterByAll();
I am unrehearsed in javascript and was hoping for some help with a next button that links to an id based on the array. Here is the array
var baseline_next=new Array();
baseline_next[0]="#one";
baseline_next[1]="#two";
baseline_next[2]="#three";
baseline_next[3]="#four";
baseline_next[4]="#five";
baseline_next[5]="#six";
baseline_next[6]="#six2";
baseline_next[7]="#seven";
baseline_next[8]="#eight";
baseline_next[9]="#nine";
baseline_next[10]="#ten";
baseline_next[11]="#eleven";
baseline_next[13]="#thirteen";
baseline_next[14]="#fourteen";
baseline_next[15]="#fifteen";
baseline_next[16]="#sixteen";
baseline_next[17]="#seventeen";
baseline_next[18]="#eighteen";
baseline_next[19]="#nineteen";
baseline_next[20]="#twenty";
baseline_next[21]="#twentyone";
baseline_next[22]="#twentytwo";
baseline_next[22]="#twentythree";
Basically what I need is, when the next button is clicked first ("0" ~ #one) I need the next buttons id to become two, and when clicked again it needs to become #three. I have no idea how to link an array to a button. The reason I need this to happen is because I am using ajax to .load div contents, so the next button doesn't actually submit, it just becomes a new next button. I dont know if it matters, but here is a part of what the button would cause to happen on click.
$('#one').click(function(){
$("#area").hide("slide", { direction: "left" }, 500);
$("#area").load("test_it.jsp #area");
$("#area").show("slide", { direction: "right" }, 500);
$("#two").show();
});
$('#two').click(function(){
if((document.form1.baseline_01[0].checked || document.form1.baseline_01[1].checked| document.form1.baseline_01[2].checked)
&& (document.form1.baseline_02[0].checked || document.form1.baseline_02[1].checked)
&& (document.form1.baseline_03_native.checked || document.form1.baseline_03_asian.checked|| document.form1.baseline_03_black.checked|| document.form1.baseline_03_pacific.checked|| document.form1.baseline_03_white.checked|| document.form1.baseline_03_other.checked)){
if(document.form1.baseline_03_other.checked && document.form1.baseline_03_other_text.value==""){
alert("Please fill in what other race you concider yourself to be.");
return false;
}else{
$("#area").hide("slide", { direction: "left" }, 500);
$("#area").load("test_it.jsp #area2");
$("#area").show("slide", { direction: "right" }, 500);
$("#three").show();
return true;
}
}else{
alert("Please select an answer for each question.");
return false;
}
});
I must apologize in advanced if my question is hard to follow, I just started coding this year.
I think that you should consider reworking your code a bit to not have this list of IDs and use a single class on all of the elements. It would help to see how your HTML is set up to get the next element based on class as well.
Since you already have this array of doom, though, I guess we'll have to use it. Ideally, you have the same class on each element. Let's say, .number.
$(".number").on('click', function () {
var nextID = baseline_next.indexOf(this.id) + 1;
});
If you can't use .number, then you can do the same thing except with a list of every ID that needs to be bound .. ouch. In the above function, nextID should be the index of the ID that comes after the clicked element.
By the way, IDs can be numbers, and you could even use data-id that contains the number. That would be easier too.
OK I really need to ask why are you doing this, are you sure that creating more than 20 ID's called like that is the better way to do want you want?
Anyways, first of all, you can create the array in a shorthand way:
var baseline_next= ["#one", "#two", "#four", "#five", "#six", "#six2" ..., "#twentythree";
(btw "#six2"? really?)
then do something like this:
var counter = 0; // start for the first one
$("#button").on('click', function () {
var id = counter++;
baseline[id]; // and I don't know what you want to do with this, but here it is!
});
Ancient question. (7 years wowzers). Here is some logic that I used for determining the next item in an array using indexOf. This will also start from the beginning once you reach the end of your array.
let options = [true,false,null];
let current = options.indexOf(this.get('order'));
let next = (current+1 > options.length-1 ? 0 : current+1);
this.set('order', options[next]);
It can be simplified as follows:
let baseline_next = ["#one", "#two", "#three"];
Don't use a var as it behaves unpredictably.
Add a variable count to change the index of the array.
let count = 0;
let baseline_next = ["#one", "#two", "#three"];
$(baseline_next[count]).click(function() {
count++;
});
Or
let count = 0;
let baseline_next = ["#one", "#two", "#three"];
$("#one").click(function() {
$(baseline_next[count]).click();
count++;
});