JavaScript: image slider changes only once upon clicking - javascript

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

Related

Opacity on first and last element of slider which has ".active" classes using javascript or css

I have owl carousel slider with 5 items. And my problem is that i need first and last element of my slider to be always with opacity. Slider has like 15 elements which 9 cloned, 5 have .active class and one with cloned and .active.
I tryied make it using javascript where i found all ".active" classes in slider, but i don't exactly know what i should do with object which was found.
There is code which found all ".active" classes
var owlCarouselActive = document.getElementById("slider-tour").getElementsByClassName("owl-item active");
I need in order to this .active first and last have :before with my background style when i click on button prev or next.
You could do this with javascript
var owlCarouselActive = document.getElementsByClassName("owl-item active");
var first = owlCarouselActive[0]; //get first item
var last = owlCarouselActive[owlCarouselActive.length - 1]; //get last item
first.style.opacity = 0.8;
last.style.opacity = 0.8;
I'm not at home but try something like this:
function setOpacity() {
var elements = $('.active');
let count = 0;
$(elements).each(function(k,v) {
if (count == 0 || count == elements.length - 1) {
$(v).css('opacity', '0.8');
}
count++;
});
}
$(document).ready(function() {
setOpacity();
});
Run that function everytime you want it to update.
E.G on a button click.
You can use owlCarouselActive [0] to access the first element and owlCarouselActive [owlCarouselActive.length-1] to access the last element. Generally you can access i-th element by owlCarouselActive [i].

Setting a limit on the number of times a note is created

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! :)

Event listener fails to attach or remove in some contexts

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.

Disable holding the up and down buttons on a jQueryUI spinner

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/

JavaScript multiple draggable DIV windows, zIndex on focus

I have multiple JavaScript draggable DIV windows. When clicking a DIV, I want the window to get the highest z-index value. I've made a solution by adding/removing classes to the element in focus, BUT, I would like the windows to keep their "layer" -order (as if the entire DIV window node was re-appended to the DOM when being clicked).
Let's say there are five DIV's in the DOM. div1, div2, div3, div4 and div5. -div5 is closest to the front and div1 is in the back and so on.
When clicking div1, -div1 will get focus and put to front, setting div5 back one step. Then clicking div3, -div3 gets closest to front and div1 and div5 are put back one step like this: div2, div4, div5, div1, div3.
If you don't want to loop through all your divs and don't want to mess up with z-index you can just append again that div to the parent element (the body?) before dragging.
function stepUpNode(elementDragged){
var parentNode = elementDragged.parentNode;
parentNode.appendChild(elementDragged);
}
If you'd like to do this without re-appending the element, my solution when I wrote something similar a while back was to keep track of the maximum z-index. Every time a window is brought forward, the maximum z-index is incremented and the element's z-index is set to the new value. Of course, if someone messes with the windows enough, they might end up having very large z-index values, so this isn't always the best solution.
var maximumZIndex = 1;
var bringForward = function (element) {
maximumZIndex += 1;
element.style.zIndex = maximumZIndex;
}
The first and most likely easiest approach: simply increase the maximum z-index every time a div gets selected. Since the z-index value can become pretty large (2147483647 if I remember correctly) you most likely will never run out of levels...
The following snippets use some jQuery:
var frontmostWindow = null;
var topZIndex = 10;
$('div').click(function() {
if (this != frontmostWindow) {
frontmostWindow = this;
topZIndex++;
$(this).css('zLevel', topZIndex);
// anything else needed to acticate your div
// ...
}
});
If you have restrictions on the z-indices you can use, you will need to re-assign levels every time a different div gets selected, e.g. like this:
// store z-index-ordered divs in an array
var divs = $('div').toArray().sort(function(a, b) {
return parseInt($(a).css('zIndex'), 10) - parseInt($(b).css('zIndex'), 10);
});
// store available z-indices
var zIndices = [];
for (var i = 0; i < divs.length; ++i) {
zIndices.push($(divs[i]).css('zIndex'));
}
// Event listener for clicks
$('div').click(function() {
alert("heyya " + this.id);
var element = this;
var index = divs.indexOf(element);
// check if clicked element is not already the frontmost
if (index < divs.length - 1) {
// remove div from array and insert again at end
divs.splice(index, 1);
divs.push(this);
// re-assign stored z-indices for new div order
for (var i = 0; i < divs.length; ++i) {
$(divs[i]).css('zIndex', zIndices[i]);
}
// anything else needed to acticate your div
// ...
}
});

Categories