I have an AngularJs directive like this:
app.directive("showSuccess", function () {
return {
restrict: "A",
link: function (_scope, _element) {
_scope.$watch("successMessage", function (newVal) {
if (newVal) {
$(_element).find("#successMessage").html(newVal);
$(_element).slideDown().delay(3000).slideUp();
}
});
// Below code does not work
$(_element).find(".hide-message").on("click", function () {
$(_element).slideUp();
_scope.successMessage = "";
});
}
};
});
The related HTML is:
<div class="ui-state-success" show-success>
<i class="icon-ok-sign small"></i>
<span id="successMessage"></span>
<i class="icon-remove hide-message"></i>
</div>
When the panel is triggered to slide down, the screen shot is:
The problem is, when I click the "×", the panel won't slide up (although that it will slide up anyway after 3s delay).
I know I can do this using ng-click. But anyone knows why it does not work in this case? Thanks.
It's because jQuery animations are queued. You're calling .slideUp() on it and expecting it to slide instantly; however, it is currently waiting out it's 3 second delay.
One solution is to use .stop(true, false) to cancel the previous queued animation:
$(_element).find(".hide-message").on("click", function () {
$(_element).stop(true, false).slideUp();
_scope.successMessage = "";
});
Related
I am using UI-Router in a project. I am using the state resolve functionality provided by the router. When I want to display a loader in between two states and I change states very often the spinner pops up but don't disappear anymore.
The same effect can be found here.
http://rp.js.org/angular-ui-view-spinner/example/index.html
If one clicks fast between the two states the loader won't hide.
I am waiting for the stateChangeStart broadcast and display the loader and on statChangeSuccess, stateChangeError and viewContentLoaded I want't to hide the loader. The stateChangeStart gets fired but stateChangeSuccess doesn't. Any idea why this behaviour appears?
I am using angular-ui-router in version 0.2.18
Here the Code for show and hide:
$rootScope.$on('$stateChangeStart', showLoading);
$rootScope.$on('$stateChangeSuccess', hideLoading);
$rootScope.$on('$stateChangeError', hideLoading);
$rootScope.$on('$viewContentLoaded', hideLoading);
function showLoading() {
$timeout(function () {
angular.element('.loading-indicator').show();
}, 50);
}
function hideLoading() {
$timeout(function () {
angular.element('.loading-indicator').hide();
}, 50);
}
You need to cancel previous timer. See documentation here: https://docs.angularjs.org/api/ng/service/$timeout.
var yourTimer;
function showLoading() {
if (yourTimer) {$timeout.cancel(yourTimer);}
yourTimer = $timeout(function () {
angular.element('.loading-indicator').show();
}, 50);
}
function hideLoading() {
if (yourTimer) {$timeout.cancel(yourTimer);}
yourTimer = $timeout(function () {
angular.element('.loading-indicator').hide();
}, 50);
}
I can't understand for which reason you use a timer for loading spinner, i recommend use only css if you use for the animation.
Here a little of my code:
HTML
<div ui-view class="fade container-fluid"></div>
<div class="spinner modal-viewer" hidden>
<div class="transparente"></div>
<div class="contenedor">
<div class="center-middle">
<div class="sk-circle">
<div class="sk-circle1 sk-child"></div>
<div class="sk-circle2 sk-child"></div>
...
<div class="sk-circle11 sk-child"></div>
<div class="sk-circle12 sk-child"></div>
</div>
</div>
</div>
</div>
You need manage them out of the uiView, because when you let out of a state, you will lose control of the state controller, then you can't disappear the spinner.
For that, put the spinner out of the uiView element, as above example.
JS
document.querySelector('.spinner')['style'].display = 'none';
My apologies for my poor previous answer.
The code is working just fine now, but is a bit sloppy and long. I'm not as proficient in js as I would like to be.
Javascript
$("#IDArea1").click(function () {
$('#indicator1').toggleClass("icon-caret-up icon-caret-down");
$('#indicator2').removeClass("icon-caret-up");
$('#indicator2').addClass("icon-caret-down");
$('#indicator3').removeClass("icon-caret-up");
$('#indicator3').addClass("icon-caret-down");
});
$("#IDArea2").click(function () {
$('#indicator2').toggleClass("icon-caret-up icon-caret-down");
$('#indicator1').removeClass("icon-caret-up");
$('#indicator1').addClass("icon-caret-down");
$('#indicator3').removeClass("icon-caret-up");
$('#indicator3').addClass("icon-caret-down");
});
$("#IDArea3").click(function () {
$('#indicator3').toggleClass("icon-caret-up icon-caret-down");
$('#indicator2').removeClass("icon-caret-up");
$('#indicator2').addClass("icon-caret-down");
$('#indicator1').removeClass("icon-caret-up");
$('#indicator1').addClass("icon-caret-down");
});
DOM Structure
<div id="IDArea1">
<i class="icon-caret-up"></i>
</div>
...
<div id="IDArea2">
<i class="icon-caret-down"></i>
</div>
...
<div id="IDArea3">
<i class="icon-caret-down"></i>
</div>
Basically, the first area (IDArea1) is open by default. Then, depending on which heading you click, will toggle the clicked heading to the opposite icon and force the others to be "icon-caret-down". So the structure of each function is the same and I have a feeling there is a cleaner way to execute this code, I just can't find a solution.
Thank you for your help.
Rename f() to something else that makes more sense to your domain:
var f = function(indicatorClicked, remainingIndicators) {
$(indicatorClicked).toggleClass("icon-caret-up icon-caret-down");
$.each(remainingIndicators, function(index, indicator) {
$(indicator).removeClass("icon-caret-up").addClass("icon-caret-down");
});
}
$("#IDArea1").click(function () { f('#indicator1', ['#indicator2', '#indicator3']) });
$("#IDArea2").click(function () { f('#indicator2', ['#indicator1', '#indicator3']) });
$("#IDArea3").click(function () { f('#indicator3', ['#indicator1', '#indicator2']) });
Yes, you can clean up your code.
You can create a function like this:
function iconCaret(el1, el2, el3, el4, el5) {
$(el1).toggleClass("icon-caret-up icon-caret-down");
$(el2).removeClass("icon-caret-up");
$(el3).addClass("icon-caret-down");
$(el4).removeClass("icon-caret-up");
$(el4).addClass("icon-caret-down");
}
Here's something you could try. Haven't tested it so it may contain typos. [id=^'IDArea'] selects elements with id starting with "IDArea".
$("[id=^'IDArea']").click(doStuff);
function doStuff(){
var num=$("[id=^'IDArea']").eq(this);
$('#indicator'+num).toggleClass("icon-caret-up icon-caret-down");
$("[id=^'indicator']").not('#indicator'+num).removeClass("icon-caret-up").addClass("icon-caret-down");
}
I am playing a bit with animate.css and jQuery on a bootstrap-based environment.
But I have a big problem!
I want to trigger animations on mouseenter / mouseleave, so I chained some complex set of callbacks, and now It's driving me crazy.
Look at my jQuery (no-conflict mode because of other plugins):
jQuery(document).ready(function () {
var animationend = "webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend animationend";
var imgRotacion = "animated rotateOut";
var h3Bounce = "animated bounceIn";
var pFlip = "animated flipInX";
var imgRotacionOff = "animated rotateIn";
var h3BounceOff = "animated bounceOut";
var pFlipOff = "animated flipOutX";
jQuery(".procaption").on("mouseenter", function () {
jQuery(this).find("img").addClass(imgRotacion).one(animationend, function () {
jQuery(this).hide();
jQuery(this).parent().find("h3").removeClass("hidden").addClass(h3Bounce).one(animationend, function () {
jQuery(this).parent().find("p").removeClass("hidden").addClass(pFlip);
});
});
});
jQuery(".procaption").on("mouseleave", function () {
jQuery(this).find("p").removeClass().addClass(pFlipOff).one(animationend, function () {
jQuery(this).removeClass().addClass("hidden");
jQuery(this).parent().find("h3").removeClass().addClass(h3BounceOff).one(animationend, function () {
jQuery(this).removeClass().addClass("hidden");
jQuery(this).parent().find("img").removeClass(imgRotacion).show().addClass(imgRotacionOff);
});
});
});
});
The HTML is pretty simple:
<div class="procaption wow fadeInLeft well text-center">
<img src="holder.js/150x150" alt="150x150" class="img-responsive img-circle center-block">
<h3 class="hidden">This is a title</h3>
<p class="hidden">But this is a description!</p>
</div>
The behavior I want to achieve:
Well, I want to chain all the animations, so they appear and disappear in some kind of order at mouseenter and mouseleave events.
Actually, it's "working" but only when mouseleaveis triggered after the last animation of mouseenter have happened.
If I try to mouseenterand instantly mouseleave, the <p>But this is a description!</p> line appears along with the <img>... That shouldn't happen!
Here's the jsFiddle.
I'm sure there should be some easier way, but I'm just learning and practicing... So any suggestion will be really appreciated!
Just for the record, I tried changing the .procaption with .procaptioningduring the animation, until the last callback is complete, but didn't work :(
I also tried $(".procaptioning").on("mouseenter mouseleave", function() { return false; }) ... without success.
Your .removeClass() functions are messing with things since they are not targeting anything. Essentially, hovering on and off quickly will cause overlapping functions to create unexpected results without specifying which classes to remove at which times. I've also made the code clearer by reducing nested this usage and using consistent selectors. See this FIDDLE for working example.
function onHoverIn(e) {
var $caption = jQuery(this),
$image = $caption.find('img'),
$h3 = $caption.find('h3'),
$desc = $caption.find('p');
$image.addClass(imgRotacion).one(animationend, function () {
$image.addClass('hidden');
$h3.removeClass('hidden').addClass(h3Bounce).one(animationend, function () {
$desc.removeClass(pFlipOff + ' hidden').addClass(pFlip);
});
});
}
function onHoverOut(e) {
var $caption = jQuery(this),
$image = $caption.find('img'),
$h3 = $caption.find('h3'),
$desc = $caption.find('p');
$desc.removeClass(pFlip).addClass(pFlipOff).one(animationend, function () {
$desc.removeClass(pFlipOff).addClass('hidden');
$h3.removeClass(h3Bounce).addClass(h3BounceOff).one(animationend, function () {
$h3.removeClass(h3BounceOff).addClass('hidden');
$image.removeClass(imgRotacion).removeClass('hidden').addClass(imgRotacionOff);
});
});
}
jQuery(".procaption").hover(onHoverIn, onHoverOut);
Hello Guys!
I have been trying to create a simple sample code for my newest jQuery Plugin, but it doesn't seems to be working at all! Can anyone tell where I'm going wrong?, or can anyone provide me a new function to do it. So my problem is that when I mouse over an element classed trigger an another element classed eg should fadeIn(); but if the user takes out the mouse before the element classed eg fades in it should not be fading in anymore, but this is not working at all. I don't not what is getting wrong? Please help me out. (Below is my Problem HTML nad Jquery Code!)
HTML CODE
<div class="trigger">MouseOverMe</div>
<div class="eg">See Me!</div>
JQUERY CODE
function timereset(a)
{
var elem = $('.'+a);
if(elem.data('delay')) { clearTimeout(elem.data('delay')); }
}
$(document).ready(function () {
$('div.eg').hide();
$('div.trigger').mouseover(function () {
$('div.eg').delay(1000).fadeIn();
});
$('div.trigger').mouseout(function () {
timereset('eg');
$('div.eg').fadeOut();
});
});
THANKS IN ADVANCE
You don't need that timereset stuff, simply call stop() on the object and the previous effect will stop:
http://api.jquery.com/stop/
Update based on the new comment:
$('div.trigger').mouseout(function () {
$('div.eg').stop().hide();
});
jQuery
$('.trigger').hover(function() {
$('.eg').delay(1000).fadeIn();
}, function() {
$('.eg').stop(true, true).hide();
});
Fiddle: http://jsfiddle.net/UJBjg/1
Another option would be to clear the queued functions like:
$('div.trigger').mouseout(function () {
$('div.eg').queue('fx', []);
$('div.eg').fadeOut();
});
Bear in mind if the fadeOut/In has already started by using stop you could end up with a semi-transparent element.
EDIT
Here's an example: http://jsfiddle.net/Qchqc/
var timer = -1;
$(document).ready(function () {
$('div.eg').hide();
$('div.trigger').mouseover(function () {
timer = window.setTimeout("$('div.eg').fadeIn(function() { timer = -1; });",1000);
});
$('div.trigger').mouseout(function () {
if(timer != -1)
window.clearTimeout(timer);
$('div.eg').fadeOut();
});
});
I have a link:
Here's my link
This is not a normal clickable link, it's coded in jQuery like this:
$("#link").hover(function(e) {
e.preventDefault();
$("#tv").stop().animate({marginLeft: "50px"});
$("#tv img)").animate({opacity: 1});
})
So after hovering unclickable link there's change of #tv's margin and opacity.
Is there any way of making this work only after the user hovers the link area with pointer for more than two seconds?
Because now everything happens in real time.
I know there's delay(), but it doesn't work because it just delays the animation and in this case I don't want any action if the pointer is over for less than two seconds.
Possible without a loop?
What you're after is called hoverIntent.
var animateTimeout;
$("#link").hover(function() {
if (animateTimeout != null) {
clearTimeout(animateTimeout);
}
animateTimeout = setTimeout(animate, 2000);
}, function() {
clearTimeout(animateTimeout);
});
function animate() {
//do animation
}
You just need a setTimeout() to delay the code, along with a clearTimeout() to clear it if the user leaves the link within 2 seconds.
Example: http://jsfiddle.net/mNWEq/2/
$("#link").hover(function(e) {
e.preventDefault();
$.data(this).timeout = setTimeout(function() {
$("#tv").stop().animate({marginLeft: "50px"});
$("#tv img)").animate({opacity: 1});
}, 2000);
}, function(e) {
clearTimeout($.data(this,'timeout'));
});