I am trying to make a simple searcher/highlighter and I am running into difficulties with inconsistent results/nothing happening when I test it out.
I think the biggest gap is my understanding of how the callback functions should work and what the selectors are able to match.
Ideally when one clicks on the tag, everything should fade out and only the dives with the matching tags in them should reappear. If nothing matches then the nothing found div should appear and the reset should fade veryhtign out and make all the divs (sans nomatch div) reappear unhighlighted.
Anyone provide some clarification on where I can improve?
Edit: See the link in the comments to see my code.
More clarification on problems:
Click on a tag (old, photography, guide) and then click on reset. All three parts should reappear but only two do.
Randomly The no results found will show up.
If you select a tag, then search for a different one, the fade ins and outs will be asynchronous.
The problem is that the .fadeout() was on each .workshopentry so would really be 3 fade outs. Therefore the animation complete callback function was being called 3 times as well! So the logic to determine which new entries to show and hide was being executed 3 times and causing the strange multiple fading.
I have updated the jsfiddle with a more robust solution.
Let me know if you need any more explanation of what the JavaScript is doing.
You need to copy your following code
if (toFadeIn.length < 1) { //No results found
toFadeIn.push(noResults);
}
$(toFadeIn).each(function(index, div){
div.fadeIn(1000);
});
inside the callback function of the workshop.fadeout.. like this :
workshop.fadeOut(1000, function() {
var tags = $('.left ul li', this);
tags.removeClass('searchMatch'); //reset the search results
tags.each(function() {
if ($(this).text().toLowerCase() === searchTerm.toLowerCase()) {
$(this).addClass('searchMatch');
toFadeIn.push($(this).parent().parent().parent());
}
});
if (searchTerm === "") {
toFadeIn.push(workshop);
}
if (toFadeIn.length < 1) { //No results found
toFadeIn.push(noResults);
}
$(toFadeIn).each(function(index, div){
div.fadeIn(1000);
});
});
You see? The fadeout callback was not yet called but you already started going through the toFadeIn array to show the search results. At that time it hadn't even searched through the entries yet.
It's only down to because we are mostly used to sequential code so callbacks take a little bit of head around. But it does work like that. You just keep on putting the code inside the callback ..and then again inside another callback and so on.
Related
I am currently making a website that includes a menu navigation almost identical to the one found at fotopunch.com only instead of pointing down it points up. Anyways, I wrote the code using jquery/javascript for the menu and it works but I am wondering if there is a way to make it so that the hover function doesn't take effect for a specified amount of time. That way when you hover quickly over an item it doesn't cause the page to load unnecessarily. If anyone has any suggestions I would greatly appreciate it.
Below is a copy of part of my code to create the menu navigation. Another issue I am having is if you hover over too many navigation items in a row the arrow lags behind. I am hoping that by creating a wait time before the hover function takes effect that it would mostly correct this issue.
$("div#menu .reps").hover(function() {
if(current_slide != "reps"){
$(".arrow").animate({"left":"135px"});//move the arrow
if(current_slide == "clients"){
$(".clients_display").stop(true, true).fadeOut().hide();
$(".reps_display").fadeIn().show();
current_slide = "reps";
}
else if(current_slide == "services"){
$(".services_display").stop(true, true).fadeOut().hide();
$(".reps_display").fadeIn().show();
current_slide = "reps";
}
else{
$(".training_display").stop(true, true).fadeOut().hide();
$(".reps_display").fadeIn().show();
current_slide = "reps";
}
}
});
I think that something that you can do, although there is probably a better way is:
declare a function where you place all the code with a condition:
function hoverFunc(option)
{
if($(option).is(':hover'))
{
all the code to show the menu
}
}
And on the over function you do:
$("div#menu .reps").hover(function() {
setTimeout("hoverFunc('"+getOptionName+"')",milliseconds);
});
The idea is: when over, set a timeout and when the timeout is reached, check if the mouse is over and then do whatever you want, the hardest point is to pass the reference to the function, but you can pass the name of the item just getting it from html or a rel attribute.
But if you dont need the reference it is really ease, just call the function and check the element.
There is another option that maybe is more interesting for you. You can add a delay to the all the effects and add a stop(true) before, this way, if the user change the tag fast, the events will be cancelled, but it will change if the user goes through an option fast and goes out of the menu.
You an use the delay on some of your calls such as:
$(".reps_display").delay(100).fadeIn().show();
Or you can make some of the show and hide have a longer duration: show(2000) for instance.
Simply put I'm trying to sync two slideshows created using widgetkit lib in a joomla website, eg. when user clicks next slide on one, the other one also runs nextSlide() function in the slideshow.js. Same for previous. The problems I'm having is widgetkit uses anonymous functions for creating those slideshows and I dont have global references to them after they are created. With my limited programming knowledge I cant seem to trigger the nextSlide function for other slideshows once inside click handler.
If anyone can take a look it would be most welcome.
EDIT:
Of course I forgot to link the example webpage
http://www.yootheme.com/widgetkit/examples/slideshow
Mine is similar with only 2 slideshows, but is still only on local server.
Taking a brief look at widgetkit here is one possible solution. Using jquery you can search for any objects that have a class of slides with a child of next and click all others. The code provided below isn't tested but should point you in the right direction. As long as you don't call stop propagation or prevent default then the original click handlers should still fire.
var slideshow_count = $('.slides .next').length;
var cascade_countdown = 0;
$('.slides .next').each(function() {
$(this).click(function() {
// stop an infinite loop if we're already cascading till we've done it for all the elements.
if(cascade_countdown != 0) {
cascade_countdown--;
return true;
}
// we don't include the slideshow we're clicking in this count
cascade_countdown = slideshow_count - 1;
var clicked_el = this;
$('.slides .next').each(function() {
// only click elements that aren't the initiator
if(this !== clicked_el) {
$(this).click();
}
});
});
});
In my HTML a#navInnerMapR and a#navInnerMapL are contained within div#navTwo.
The following code is within a function. When called, I need the function to fadeOut any visible links in div#navTwo, pause for a moment, and then fadeIn a#navInnerMapR.
$('div#navTwo a').fadeOut(200, function() {
$('a#navInnerMapR').delay(100).fadeIn(200);
});
The code fades out the links but doesn't fade anything in. I thought that they delay would only start once the fadeOut finishes, however changing the delay value to 1000 makes it sometimes work but its very buggy. Thanks
UPDATE Here is a fiddle showing that the hidden link starts to be shown before the visible is hidden: http://jsfiddle.net/jamesbrighton/d9QKr/5/
UPDATE Apologies, my question doesnt include the full details of what I need to achieve. I simplified it as I thought I just had some sort of sytax issus that could be easily fixed.
div#navTwo actually contains 3 links. At any point (other than the delay before animations run) only 1 link is visible. I need to be able to call a function that will hide either of the other 2 links that are being shown, and then show a#navInnerMapR.
Different events will call this function, so either of the 2 links that arn't a#navInnerMapR may be visible. Thanks
UPDATE I think this fiddle illustrates the issue. Ive created 2 div.nav's to illustrate different states. Ive hidden different links with inline CSS in each one. JavaScript will be showing and hiding the links in my div repeatedly, so the same div will look like each example at different times.
Ive created 2 triggers to illustrate that different events will need to call the function. When you click on a trigger you can see the issue with both examples. The visible divs are not hidden before the a.one is shown. Thanks for your patience!
http://jsfiddle.net/jamesbrighton/dYvMS/24/
Interesting point, if I change $('.nav a.one').fadeIn(1000); to an alert, the alert fires multiple times! No idea why this would be the case!
Edit: Updated answer based on your below comment,
Yes this works as I need, but im not sure it will work for my actual
page. Sorry for my question not being detailed enough. The code
example I gave is simplified. In the actual page their are 3 links
within div#navTwo, at any time only one of them will be visible. I
need to be able to call a function that hides any links and shows a
specific one, but either one of the other 2 links in div#navTwo may be
visible. Thanks
DEMO
HTML: Added class to all links inside navTwo
<div id="navTwo">
Right
Left
Middle
Upper
Lower
</div>
JS:
$('.links').click(function() {
showHide($(this));
});
function showHide($this) {
$this.fadeOut(1000, function() {
$('#navTwo a').not($this).delay(1000).fadeIn(1000);
});
}
I think I understood what you need. Try below DEMO and let me know if that is what you want,
DEMO
$('#navInnerMapR').click(function() {
runMeR($(this));
});
$('#navInnerMapL').click(function() {
runMeL($(this));
});
function runMeR($this) {
$this.fadeOut(1000, function() {
$('a#navInnerMapL').delay(1000).fadeIn(1000);
});
}
function runMeL($this) {
$this.fadeOut(1000, function() {
$('a#navInnerMapR').delay(1000).fadeIn(1000);
});
}
As you said, You need the function to fadeOut any visible links in div#navTwo, pause for a moment, and then fadeIn a#navInnerMapR (not other links, only a#navInnerMapR).
$('#navTwo a').click(function(e) {
$(this).parent().children().each(function(i){
$(this).fadeOut('slow', function(){
$('a#navInnerMapR').delay(1000).fadeIn(1000);
});
});
});
A fiddle is here.
I'm looking for some help to implent a timer for this script I'm linking to.
As it is now, it toggles different slides when hovering the list to the right, but I want the slider to automatically jump ahead to the next slide after a certain amount of time until it reaches the end and then goes back to the top.
The catch though is that it also needs to work as it is now, so that you can toggle via hovering and when you stop hovering it should remember the position and jump ahead to the next item.
I realize this is alot to ask for, but some pointer would be great, thanks alot!
DEMO: http://jsbin.com/acorah
Your code is taking a bit of a performance hit with that each() loop which I don't think you need. You're binding events inside the loop and you're limiting your possibilities by declaring your actions inside the bind() scope. You want to be able to call events on any object and not only a single element; $('.cn_item') in your case.
The idea is to keep track of your current slide with a class, let's say .cur.
Then you create an object where you declare all your methods. The main methods or actions are getCur() and goTo() and mostly everything else will use these. ie. next() is just a shortcut for goTo()
var actions = {
getCur: function(){ return idx; },
goTo: function(idx){
// The simplest case
$slides.hide().eq(idx).show();
},
next: function(){ this.goTo(this.getCur()+1); },
prev: function(){ this.goTo(this.getCur()-1); }
.
.
.
}
Now you can call actions on events by simply doing this:
$slides.click(function(){ actions.goTo($(this).index()); });
$next.click(function(){ actions.next(); });
And then you can setInterval() to add a timer.
setInterval(actions.next, 1000);
This tutorial might help. I basically cover everything involved in making a slider. I would change some things as of today, we learn new ways to code stuff everyday.
We're trying to make sure our JavaScript menu, which loads content, doesn't get overrun with commands before the content in question loads and is unfurled via .show('blind', 500), because then the animations run many times over, and it doesn't look so great. So I've got about six selectors that look like this:
("#center_content:not(:animated)")
And it doesn't seem to be having any effect. Trying only :animated has the expected effect (it never works, because it doesn't start animated), and trying :not(div) also has this effect (because #center_content is a div). For some reason, :not(:animated) seems not to be changing the results, because even when I trigger the selector while the div in question is visibly animated, the code runs. I know I've had success with this sort of thing before, but the difference here eludes me.
$("#center_content:not(:animated)").hide("blind", 500, function () {
var selector_str = 'button[value="' + url + '"]';
//alert(selector_str);
var button = $(selector_str);
//inspectProperties(button);
$("#center_content:not(:animated)").load(url, CenterContentCallback);
if (button) {
$("#navigation .active").removeClass("active");
button.addClass("active");
LoadSubNav(button);
}
});
I hope this provides sufficient context. I feel like the second selector is overkill (since it would only be run if the first selector succeeded), but I don't see how that would cause it to behave in this way.
Here's the snippet that seemed to be working in the other context:
function clearMenus(callback) {
$('[id$="_wrapper"]:visible:not(:animated)').hide("blind", 500, function() {
$('[id^="edit_"]:visible:not(:animated)').hide("slide", 200, function() {
callback();
});
});
}
Here, the animations queue instead of interrupt each other, but it occurs to me that the selector still doesn't seem to be working - the animations and associated loading events shouldn't be running at all, because the selectors should fail. While the queueing is nice behavior for animations to display, it made me realize that I seem to have never gotten this selector to work. Am I missing something?
Sometimes it's helpful to use .stop() and stop the current animation before you start the new animation.
$("#center_content").stop().hide("blind", 500, function () {});
Really depends on how it behaves within your environment. Remember that .stop() will stop the animation as it was (eg. halfway through hiding or fading)
I don't know if I understand it correctly, but if you want to make sure the user doesn't trigger the menu animation again while it's currently animating(causing it to queue animations and look retarded, this works and should help. I use an if-statement. And before any mouseover/off animation I add .stop(false, true).
$('whatever').click(function(){
//if center_content is not currently animated, do this:
if ($("#center_content").not(":animated")) {
$(this).hide(etc. etc. etc.)
}
//else if center_content IS currently animated, do nothing.
else {
return false;}
});
another example i found elsewhere:
if($("#someElement").is(":animated")) {
...
}
if($("#someElement:animated").length) {
...
}
// etc
then you can do:
$("#showBtn").attr("disabled", $("#someElement").is(":animated"));