jQuery: wait to perform a task until an animation finished - asp.net

I have a div which is placed in any pages. When you click on this div, it will be closed by using jquery checking on its css class:
$('.content-box-header').click(function
() {
$(this).parent().children('.content-box-content').slideFadeToggle(200);
}
In several pages, I need to set that div with a specific ID in order to perform some tasks after that div closed. For example:
$('#divleft').live('click', function
(e) { runTask(); }
The above sample is trigger on that div with the specific ID = divleft.
The problem is that, I would like to check something ONLY after the div is really closed, but in my current situation, runTask() is performed before the div is closed.
SO my question is that how could the method runTask(); is delayed after the div is really closed?
Thanks in advance!!!!

I think what you are looking for is .queue(). See the documentation here: http://api.jquery.com/queue/
You can call this on a set of matched elements to get some information about the remaining effects to be run. So in your case you could do something like this:
$('#divleft').live('click', function (e) {
runTaskAfterAnimation()
});
function runTaskAfterAnimation() {
if ($('.content-box-content').queue('fx').length == 0) {
runTask();
} else {
setTimeout(runTaskAfterAnimation, 10);
}
}
View a demonstration here: http://jsfiddle.net/LeHHj/2/
This time it definitely works ;)

In your case, just use
$('.content-box-header').click(function () { $(this).parent().children('.content-box-content').slideFadeToggle(200, function() { runTask(); }); }

You can store the function on the div using jQuery's data() method.
This lets you set an 'afterClick' function on your element:
$('.content-box-header').click(function () {
var $this = $(this);
$this.parent().children('.content-box-content').slideUp(200, function () {
var after = $this.data('afterClick');
if (after) after();
});
});
$('#divleft').data('afterClick', function () { runTask(); });

You need to check if the item you are wanting to runTask() on is :animated and if so 'register' a callback (via .data()) for when it's done
.live('click', doRunTask);
doRuntask = function() {
if ($(this).is(':animated'))
$(this).data('afterAnimation', runTask);
else
runTask();
});
$('.content-box-header').click(function () {
$(this).parent().children('.content-box-content').slideFadeToggle(200, function() {
var cb = $(this).data('afterAnimation');
cb && cb();
});
}

Related

Multiple IDs in one code

I have this code for limiting checkboxes in a form and I want to know if it's possible for me to utilize it with more than one ID, something like 10 options limit between those two forms(The IDs are iphorm_1_10 and iphorm_1_12)
Thanks!
<script>
jQuery(document).ready(function ($) {
var $checkboxes = $('.iphorm_1_10');
$checkboxes.click(function () {
var checked = 0;
$checkboxes.each(function () {
if ($(this).is(':checked')) {
checked++;
}
});
if (checked > 10) {
alert('You can only select 10 options')
$(this).prop('checked', false);
$.uniform.update();
return false;
}
});
});
I am confused. $('.iphorm_1_10'); refers to CLASS .iphorm_1_10 and not ID, am i wrong? If you use classes, just give your forms the same class. If you want to use ID's, repeat your .each for every ID you got.

How to return number of items in collection?

I'm new to Meteor and I want to create a slideshow with items from a collection, in this case simple words. The slideshow should be controlled by back and forward buttons and replace the current word.
In JavaScript/jQuery I would create an array of objects and a control index, with limits via if-statements, so the index never can drop below zero or overflow the length of the array.
See fiddle for working example:
http://jsfiddle.net/j0pqd26w/8/
$(document).ready(function() {
var wordArray = ["hello", "yes", "no", "maybe"];
var arrayIndex = 0;
$('#word').html(wordArray[arrayIndex]);
$("#previous").click(function(){
if (arrayIndex > 0) {
arrayIndex -= 1;
}
$('#word').html(wordArray[arrayIndex]);
});
$("#next").click(function(){
if (arrayIndex < wordArray.length) {
arrayIndex += 1;
}
$('#word').html(wordArray[arrayIndex]);
});
});
Meteor
I'm curious how to implement this in regards to best practice in meteor and abide to the reactive pattern as I'm still trying to wrap my head around this interesting framework. My first hurdle is to translate the
if (arrayIndex < wordArray.length)
// to
if (Session.get("wordIndex") < ( (((length of collection))) )
According to the docs I should do a find on the collection, but I have only manage to return an empty array later with fetch. Sorry if this got long, but any input would be appreciated to help me figure this out.
collection.find([selector], [options])
cursor.fetch()
This is the code I have so far:
Words = new Mongo.Collection("words");
if (Meteor.isClient) {
// word index starts at 0
Session.setDefault("wordIndex", 0);
Template.body.helpers({
words: function () {
return Words.find({});
},
wordIndex: function () {
return Session.get("wordIndex");
}
});
Template.body.events({
"submit .new-word": function (event) {
// This function is called when the word form is submitted
var text = event.target.text.value;
Words.insert({
text: text,
createdAt: new Date() //current time
});
// Clear form
event.target.text.value = "";
// Prevent default form submit
return false;
},
'click #previous': function () {
// decrement the word index when button is clicked
if (Session.get("wordIndex") > 0) {
Session.set("wordIndex", Session.get("wordIndex") - 1);
}
},
'click #next': function () {
// increment the word index when button is clicked
if (Session.get("wordIndex") < 10 ) {
Session.set("wordIndex", Session.get("wordIndex") + 1);
}
}
});
}
if (Meteor.isServer) {
Meteor.startup(function () {
});
}
.count() will return the number of documents in a collection.
`db.collection.count()`
There is something called Collection helpers, which works similar to other helpers (eg., template, etc.,). More elaborate explanation is covered here: https://medium.com/space-camp/meteor-doesnt-need-an-orm-2ed0edc51bc5

Deep link to a position in a page, using Meteor JS

I have a meteor app with multiple pages. I want to be able to deeplink to an anchor somewhere halfway the page.
Traditionally, in normal html, you'd make an somewhere in your page, and link to it via /mypage.html#chapter5.
If I do this, my meteor app won't scroll down to that spot.
What is the best approach around this?
#Akshat 's answer works for on the same page, but what if you want to be able to pass around a url w/ a "#" in it? I did it how the meteor docs did.
Template.myTemplate.rendered = function() {
var hash = document.location.hash.substr(1);
if (hash && !Template.myTemplate.scrolled) {
var scroller = function() {
return $("html, body").stop();
};
Meteor.setTimeout(function() {
var elem = $('#'+hash);
if (elem.length) {
scroller().scrollTop(elem.offset().top);
// Guard against scrolling again w/ reactive changes
Template.myTemplate.scrolled = true;
}
},
0);
}
};
Template.myTemplate.destroyed = function() {
delete Template.myTemplate.scrolled;
};
Stolen from the source to the meteor docs.
Are you using some kind of javascript router? Meteor Router?
You could use something like a javascript based scrolling method. One such example is with JQuery: (You can place this in your link/buttons click handler)
Template.hello.events({
'click #theitemtoclick':function(e,tmpl) {
e.preventDefault();
$('html, body').animate({
scrollTop: $("#item_id").offset().top
}, 600);
}
});
Then tag your html item where you would put your anchor with the id:
<h1 id="item_id">Section X</h1>
Currently, there's an issue in IronRouter where the hash is removed from the url. This is discussed here and here. Fortunately there is a fix even though it doesn't appear to be in the stable version.
My Iron Router solution with traditional anchor tags:
1) Apply the IronRouter fix above
2)
Router.configure({
...
after: function () {
Session.set('hash', this.params.hash);
},
...
});
3)
function anchorScroll () {
Deps.autorun(function (){
var hash = Session.get('hash');
if (hash) {
var offset = $('a[name="'+hash+'"]').offset();
if (offset){
$('html, body').animate({scrollTop: offset.top},400);
}
}
Session.set('hash', '');
});
}
Template.MYTEMPLATE.rendered = function (){
anchorScroll();
};
Unfortunately this has to be set in each template's .rendered() otherwise the anchor tag is not guaranteed to be in the DOM.
For better or worse this will scroll again with a code push.
Mike's Answer didn't quite work for me. The hash was returning empty in the onRendered callback. I nested the code in an additional Meteor.setTimeout
fyi I'm using Blaze.
Below worked like a charm :)
Template.myTemplate.onRendered(function() {
Meteor.setTimeout(function(){
var hash = document.location.hash.substr(1);
if (hash && !Template.myTemplate.scrolled) {
var scroller = function() {
return $("html, body").stop();
};
Meteor.setTimeout(function() {
var elem = $("a[name='" + hash + "']");
if (elem.length) {
scroller().scrollTop(elem.offset().top);
// Guard against scrolling again w/ reactive changes
Template.myTemplate.scrolled = true;
}
},
0);
}
},0);
});
Template.myTemplate.destroyed = function() {
delete Template.myTemplate.scrolled;
};

jquery disable a button for a specific time

i want to disable a button for a specific time. how can i do that?
Since this is likely to be a task you might like to repeat, I think the best way to do this would be to extend jQuery like so:
$.fn.timedDisable = function(time) {
if (time == null) { time = 5000; }
return $(this).each(function() {
$(this).attr('disabled', 'disabled');
var disabledElem = $(this);
setTimeout(function() {
disabledElem.removeAttr('disabled');
}, time);
});
};
This will allow you to call a function on a set of matched elements which will temporarily disable them. As it is written, you can simply call the function, and the selected elements will be disabled for 5 seconds. You would do that like so:
$('#some-button').timedDisable();
You can adjust the default time setting by changing the 5000 in the following line:
if (time == null) { time = 5000; }
You can optionally pass in a time value in milliseconds to control how long the elements will be disabled for. For example:
$('#some-button').timedDisable(1000);
Here's a working demo: http://jsfiddle.net/fG2ES/
Disable the button and then use setTimeout to run a function that enables the button after a few seconds.
$('#some-button').attr("disabled", "disabled");
setTimeout('enableButton()', 5000);
function enableButton(){
$('#some-button').removeAttr('disabled');
}
Try this.
(function(){
$('button').on('click',function(){
var $this=$(this);
$this
.attr('disabled','disabled');
setTimeout(function() {
$this.removeAttr('disabled');
}, 3000);
});
})();
You can find a working example here http://jsfiddle.net/informativejavascript/AMqb5/
Might not be the most elegant solution, but I thought I'd play with jQuery queues on this one...
​$.fn.disableFor = function (time) {
var el = this, qname = 'disqueue';
el.queue(qname, function () {
el.attr('disabled', 'disabled');
setTimeout( function () {
el.dequeue(qname);
}, time || 3000);
})
.queue(qname, function () {
el.removeAttr('disabled');
})
.dequeue(qname);
};
$('#btn').click( function () {
​$(this).disableFor(2000);​​​​
});
​
This is where I worked it out... http://jsfiddle.net/T9QJM/
And, for reference, How do I chain or queue custom functions using JQuery?

Scope problem with SetTimeOut

I don't know why but this code is not working ? Why would it not ? I guess it is because scope problem I am having here :
function washAway(obj) {
alert($(obj)); // says HTML Object which is fine
setTimeout(function() {
alert($(obj)); // says undefined
$(obj).fadeOut("slow", function() {
$(this).remove();
});
}, 2000);
};
At the point where the function in the timeout executes, it has no way to know what obj is - it was a parameter passed into the method where the timeout was set up, but the function inside has no reference to it.
An alternative approach is to write a jQuery plugin to wait before it acts like this:
function($){ //to protect $ from noConflict()
$.fn.pause = function(duration) {
$(this).animate({ dummy: 1 }, duration);
return this;
};
}
Then you can use:
$(obj).pause(2000).fadeOut("slow", function() { $(this).remove(); });
Any ways, I've found my answer after a couple of try/wrong. But I am still wondering why it didn't work out.
Here is the code :
function washAway(obj) {
alert($(obj).attr("id"));
var a = function() {
var _obj = obj;
return function() {
$(_obj).fadeOut("slow", function() {
$(this).remove();
});
};
};
setTimeout(a(), 2000);
};
Edit : I think I understood the problem here :
Because we are talking about closures here, when washAway execution finishes, the variable obj is destroyed so setTimeOut function callback function can't use that resource because it is no more available on the stack and it is not also a global variable.

Resources