JavaScript: Slider jumps to the wrong ID every 2 steps - javascript

I've built a custom, dirt and quick, jQuery/JavaScript slider... which works great, except for one issue.
When using the 'Previous' button, it works perfectly the first time you click it, but then when you click it again, the length of the array becomes '2' when it should be '1' because there are only two results...
Code:
jQuery("#sliderNext").click(function(event) {
$("#sliderNext").fadeOut(50);
$("#sliderPrevious").fadeOut(50);
setTimeout(function() {
$("#sliderNext").fadeIn(100);
$("#sliderPrevious").fadeIn(100);
}, 900);
slideNumber++;
if(slideNumber < image.length && caption.length) {
jQuery(".slider-image").css("background-image", "url(" + image[slideNumber] + ")");
jQuery("#caption").text(caption[slideNumber]);
console.log("if: " + slideNumber);
}
else
{
slideNumber = 0;
jQuery(".slider-image").css("background-image", "url(" + image[slideNumber] + ")");
jQuery("#caption").text(caption[slideNumber]);
console.log("else: " + slideNumber);
}
});
jQuery("#sliderPrevious").click(function(event) {
$("#sliderNext").fadeOut(50);
$("#sliderPrevious").fadeOut(50);
setTimeout(function() {
$("#sliderNext").fadeIn(100);
$("#sliderPrevious").fadeIn(100);
}, 900);
slideNumber--;
console.log(image.length);
if(slideNumber >= 0 && slideNumber <= image.length) {
jQuery(".slider-image").css("background-image", "url(" + image[slideNumber] + ")");
jQuery("#caption").text(caption[slideNumber]);
console.log("if: " + slideNumber);
}
else
{
slideNumber = image.length;
jQuery(".slider-image").css("background-image", "url(" + image[slideNumber] + ")");
jQuery("#caption").text(caption[slideNumber]);
console.log("else: " + slideNumber);
console.log(image.length);
}
});
I've tried using different operators, if/else statements, it always sets it to 2 on the second click.
Could anybody point me in the right direction for why it would do this?

This might be because your click event gets bound the second time to the button and therefore jumps twice.
Try to "unbind" your click events before binding them.
$("#sliderPrevious").unbind();
// and then
jQuery("#sliderPrevious").click(function(event) {...});
Do this to every event that gets bound when intializing the page.
EDIT
var myArray = [a,b];
Note that myArray.length == 2 but myArray[2] is undefined.
Array indexes start at [0] thats why you have to substract 1 from your "counter" variable.

Related

jQuery - why do 2 elements get appended when I click an icon

I've created a JSfiddle here:
basically I have a form that will allow users to input additional sections... but when I have added more than 2 units and then proceed to click on the 'plus' (+) icon I get more than 1 element created in that section... its probably something elementary, but any info will help.
Move your Click functions out of the click function
//add unit input box and increment click counter by one.
addUnit.click(function () {
unitCounter += 1;
unitElementCount = jQuery(".unit-element").length;
if (unitCounter <= 4) {
error.hide();
container.append('<table id="unit-' + unitCounter + '-div" class="create-course-table-element unit-element"><tr><td><label class="unit-label">Unit ' + unitCounter + '</label></td><td><input class="create-course-input-element unit-input" id="unit-id-' + unitCounter + '" name="unit-' + unitCounter + '" /><div id="delete-unit-' + unitCounter + '" class="ui-icon ui-icon-circle-close del-unit" title="Delete unit"></div></td></tr><tr><td align="center">Sections</td><td><div id="add-section-icon-' + unitCounter + '" class="ui-icon ui-icon-plus add-section-icon"></div></td></tr></table><div id="section-id-' + unitCounter + '-div" class="this-section"></div>');
} else if (unitElementCount == 4) {
unitCounter = 5;
error.html("");
error.fadeIn(1500);
error.append("<p class='error-message'>Note: You are only able to add 4 units to a given course. Each unit allows you to add 10 separate sections of content; therefore you may add a total of 40 different sections to a given course. If the material requires more units, you should consider dividing the course into 2 parts.</p>");
}
});
//This part has been slightly modified and moved out of the addUnit.click() function
var counterSecTwo = 0;
var counterSecThree = 0;
var counterSecFour = 0;
jQuery(document).on("click", "#add-section-icon-2",function () {
counterSecTwo += 1;
var container = jQuery("#section-id-2-div");
container.append("<p>test "+counterSecTwo+"</p>");
});
jQuery(document).on("click", "#add-section-icon-3",function () {
counterSecThree += 1;
var container = jQuery("#section-id-3-div");
container.append("<p>test "+counterSecThree+"</p>");
});
jQuery(document).on("click", "#add-section-icon-4",function () {
counterSecFour += 1;
var container = jQuery("#section-id-4-div");
container.append("<p>test "+counterSecFour+"</p>");
});
});
Here I am binding the click handlers to Document as the elements do not exist yet: you could also add the event listener when you create the actual element.
Modified fiddle: http://jsfiddle.net/vewP7/

goog.ui.ProgressBar weird behaviour

I have to load a very big JSON object and perform various expensive processes. For this reason, I am showing a progress bar which increments a total of five times. If I have to load 10000 items, it will update every 2000 times, etc.
The problem is the effect is not visible because all the stack executes after the entire function is complete, instead of updating the progressbar at every 20% of the process. It doesn't matter if I try to load 10000 items or 2 million items, same stuff happens, and judging by the computation delay between console logs, there is definitely enough processing time to show a visible progress effect. Perhaps I'm not understanding the javascript for(I know this wasn't the way to do it). How do you track an expensive process and make a visible progress bar effect properly?
This is the js file.
login with
username : admin
password: testit
var initItems = function(publicationItems) {
var publications = new Array();
var numberOfItems = goog.object.getCount(publicationItems);
var minStep = 20;
var currentProgress = 20;
var progressBarStep = parseInt(numberOfItems / 5);
var i = 0;
goog.object.forEach(publicationItems, function() {
var currentName = publicationItems.name;
var currentCat = publicationItems.categories;
// Insert clear div to break line after every 5 items.
if (i % 5 == 0 && i != 0)
publications.push(this.clear);
if(i % progressBarStep == 0)
{
progressBar.setValue(currentProgress);
console.log(i + ' ' + progressBarStep + ' ' + currentProgress + ' ' + progressBar.getValue());
currentProgress += minStep;
}
i++;
publications.push(goog.dom.createDom('div', {
'style' : 'width:' + this.currentPublicationDimension + 'px;height:' +
this.currentPublicationDimension + 'px;border:1px solid #B3B3B3;' +
'float: left;margin-top: 5px;background-color: #FCFCFC;' +
'max-width:' + this.currentPublicationDimension + 'px;max-height:' +
this.currentPublicationDimension + 'px;_height:' +
this.currentPublicationDimension +
'px;_width:' + this.currentPublicationDimension + 'px;margin-left:' +
this.publicationLeftMargin + 'px;',
'class' : 'publication'
}, currentName, currentCat));
}, this);
return publications;
};
And the context from where this function was called:
// Bind COMPLETE event listener to ajaxHandler.
goog.events.listen(ajaxHandler, goog.net.EventType.SUCCESS,
goog.bind(function(e) {
//goog.style.showElement(progressBarContainer, false);
goog.dom.append(this.mainViewPublications, initItems.call(this, e.target.getResponseJson()));
}, this), false, this);
The problem is that JavaScript is Singlethreaded and first tries to execute the calculations. The ProgressBar is asynchronous and will only update, if the thread is not busy.
You could use callbacks like following
function a () {
/* do one iteration */
progressBar.setValue(currentProgress);
goog.Timer.callOnce(a, 10);
}
The Problem with that, is that you can't pass parameters to the function and you have to use global variables (or at least 'object' wide variables).
I currently have the same issue and haven't found a really good solution. So this is a first approach. If I find another solution I will update it here.

Showing matching lines from a search using jquery

I have a bit of code that searches the current information shown on the page from a input source, which is an XML loaded in. This then shows how many times the word has been found, it should then display the lines where the word was found although currently it is showing all the lines. The code is
function searchResults(query) {
var temp = "\\b" + query + "\\b";
var regex_query = new RegExp(temp, "gi");
var currentLine;
var num_matching_lines = 0;
$("#mainOutput").empty();
$("LINE", g_playDOM).each(
function() {
currentLine = $(this).text();
matchesLine = currentLine.replace(regex_query,
'<span class="query_match">' + query + '</span>');
if (currentLine.search(regex_query) > 0)
num_matching_lines++;
$("#mainOutput").append("<p>" + matchesLine + "</p>");
});
$("#sideInfo").append(
"<p>Found " + query + " in " + num_matching_lines + " lines</p>");
}
$(document).ready(function() {
loadPlay();
$("#term_search").focus(function(event) {
$(this).val("");
});
$("#term_search").keypress(function(event) {
if (event.keyCode == 13)
searchResults($("#term_search").val());
});
$('#term-search-btn').click(function() {
searchResults($("#term_search").val());
});
});
</script>
Currently the number of lines the word is on is being shown correctly.
If you want a line of code to be executed within a conditional, then you need to place curly braces around it. Otherwise, only the very next action item will be executed. In your case, increase the count of the number of lines that match.
Your subsequent action item, appending the found line into the DOM is executed on every branch because the if statement has already done its job. Offending lines below:
if ( currentLine.search(regex_query) > 0 ) num_matching_lines++;
$("#mainOutput").append("<p>" + matchesLine + "</p>");
Fixed:
if ( currentLine.search(regex_query) > 0 ) {
num_matching_lines++;
$("#mainOutput").append("<p>" + matchesLine + "</p>");
}

DIV Not Being Generated in IE7 with jQuery

I can't figure out why this script isn't working in IE7 and 8. It works fine in all other browsers, but for some reason, in IE7 and 8 this script is only firing the // thumbs hover bit, and not the // loading images bit (which is actually more important). Everything seems to be fine, does anyone have any ideas?
function featuredJS() {
$("[title]").attr("title", function(i, title) {
$(this).data("title", title).removeAttr("title");
});
// loading images
var last = "featured/01.jpg";
$("#thumbs a").click(function(event) {
event.preventDefault();
var position = $(this).attr("class");
var graphic = $(this).attr("href");
var title = $(this).attr("alt");
var description = $(this).data("title");
var currentMargin = $("#full-wrapper #full").css("marginLeft");
var currentWidth = $("#full-wrapper #full").css("width");
var transitionTest = currentMargin.replace("px", "") * 1;
if(last != graphic && ((transitionTest % 938) == 0 || transitionTest == 0)) {
$("#placeholder").before( "<div class='featured'><div class='description " + position + "'>" + "<h3>" + title + "</h3>" + "<p>" + description + "</p>" + "</div><img src=\"" + graphic + "\" /><div style='clear:both;'></div></div>" );
$("#full-wrapper #full").animate({
marginLeft: "-=938px"
}, 500);
$("#full-wrapper #full").css("width","+=938px");
last = graphic;
};
});
// thumbs hover
$("#thumbs .thumb").hover(
function () {
$(this).find(".red-bar").animate({height:"72px"},{queue:false,duration:500});
},
function () {
$(this).find(".red-bar").animate({height:"3px"},{queue:false,duration:500});
}
);
};
Demo page at http://www.weblinxinc.com/beta/welex/demo/
Your problem is caused by not having a margin set to begin with. transitionTest then becomes NaN because the style is auto, not 0px like you're expecting. Consider trying this instead:
var transitionTest = parseInt("0"+currentMargin,10);
This will trim off the "px" for you, as well as handle the case where the margin is a keyword.

Can't find the issue: javascript/jQuery

I have the following function that gets called on the KeyDown event of a link.
Basically I'm trying to move down the table (the application calls it a ListBox). In the first loop what I'm trying to do is see if they use the mouse to click inside the table first and my hope was to find the row value and then manipulate the class (highlight) from there.
Unfortunately right now I'm not even getting that far. When the screen loads and I press the down button, the current row (0) has it's class changed as well as row (1). But on the next down button press the tr_lst says it is undefined. Which then throws the loop off and then I get all sorts of errors.
I tried to implement a jsfiddle, however, I couldn't get it working. But you can see some of the code I'm trying to implement.
function xKeyDown(event,ListBoxVal){
var tr_lst = $('#' + ListBoxVal).find('tr[class="LUGridRowHighlight"]');
var iCount = 0;
for (iCount = 0; iCount <= $('#' + ListBoxVal + ' tr').length; iCount++){
if($('#' + ListBoxVal + ' tr:eq('+iCount+')').attr('id') == tr_lst.attr('id')){
lstRow = iCount;
break;
}
}
if (event.keyCode == 40){
//arrow down
if(parseInt(lstRow) < $('#' + ListBoxVal + ' tr').length)
{
if(parseInt(lstRow) == 0){
document.getElementById(ListBoxVal).focus();
lstRow +=1;
document.getElementById($('#' + ListBoxVal + ' tr:eq('+parseInt(lstRow)+')').attr('id')).focus();
$('#' + ListBoxVal + ' tr:eq('+parseInt(lstRow)+')').addClass('LUGridRowHighlight');
$('#' + ListBoxVal + ' tr:eq('+parseInt(lstRow)+')').prev().removeClass('LUGridRowHighlight') .addClass('LUGridRow');
}else{
document.getElementById($('#' + ListBoxVal + ' tr:eq('+parseInt(lstRow)+')').attr('id')).focus();
$('#' + ListBoxVal + ' tr:eq('+parseInt(lstRow)+')').addClass('LUGridRowHighlight');
$('#' + ListBoxVal + ' tr:eq('+parseInt(lstRow)+')').prev().removeClass('LUGridRowHighlight') .addClass('LUGridRow');
lstRow +=1;
}
}
...
Update:
After looking into this further... It appears that when I click the down arrow more than once the following code is causing an error:
var tr_lst = $('#' + ListBoxVal).find('tr[class="LUGridRowHighlight"]');
When I try to print this out it is 'undefined'
I'm wondering since I am manipulating the class via jQuery do I need to add a .live somewhere to the find? As I believe when elements are manipulated dynamically the .live comes into play. Any suggestions?
Try this
function xKeyDown(event,ListBoxVal){
var $listBoxVal = $('#' + ListBoxVal);
var trs = $listBoxVal.find('tr');
var tr_lst = $listBoxVal.find('tr.LUGridRowHighlight');
var tr_lst_id = tr_lst.attr('id');
var iCount = 0;
for (iCount = 0; iCount <= trs.length; iCount++){
if($listBoxVal.find('tr:eq('+iCount+')').attr('id') == tr_lst_id){
lstRow = iCount;
break;
}
}
if (event.keyCode == 40){
//arrow down
if(parseInt(lstRow) < $listBoxVal.find('tr').length)
{
if(parseInt(lstRow) == 0){
$listBoxVal.focus();
lstRow +=1;
$("#"+$listBoxVal.find('tr:eq('+parseInt(lstRow)+')').attr('id')).focus();
$listBoxVal.find('tr:eq('+parseInt(lstRow)+')').addClass('LUGridRowHighlight');
$listBoxVal.find(' tr:eq('+parseInt(lstRow)+')').prev().removeClass('LUGridRowHighlight').addClass('LUGridRow');
}else{
$("#"+$listBoxVal.find('tr:eq('+parseInt(lstRow)+')').attr('id')).focus();
$listBoxVal.find('tr:eq('+parseInt(lstRow)+')').addClass('LUGridRowHighlight');
$listBoxVal.find('tr:eq('+parseInt(lstRow)+')').prev().removeClass('LUGridRowHighlight').addClass('LUGridRow');
lstRow +=1;
}
}
...

Categories