diff --git a/order.json b/order.json index 8527b06a..ee998761 100644 --- a/order.json +++ b/order.json @@ -59,8 +59,7 @@ "effects": [ "intro-to-effects", "custom-effects", - "queue-and-dequeue-explained", - "uses-of-queue-and-dequeue" + "queue-and-dequeue-explained" ] }, { diff --git a/page/effects/queue-and-dequeue-explained.md b/page/effects/queue-and-dequeue-explained.md index c527d75f..b72cfaec 100644 --- a/page/effects/queue-and-dequeue-explained.md +++ b/page/effects/queue-and-dequeue-explained.md @@ -4,53 +4,115 @@ "source": "http://jqueryfordesigners.com/api-queue-dequeue/" } -When you use the `.animate()`, `.show()`, `.hide()`, `.slideUp()`, etc. effect methods, you're adding a job to the effects queue. By default, using `.queue()` and passing a function, will add it to the effects queue. So we're creating our own bespoke animation step: +Queues are the foundation for all animations in jQuery, they allow a series functions to be executed asynchronously on an element. Methods such as `.slideUp()`, `.slideDown()`, `.fadeIn()`, and `.fadeOut()` all use `.animate()`, which leverages *queues* to build up the series of steps that will transition one or more CSS values throughout the duration of the animation. + +We can pass a callback function to the `.animate()` method, which will execute once the animation has completed. ``` $( ".box" ) - .animate({ + .animate( { height: 20 - }, "slow" ) - .queue(function() { - $( "#title" ).html( "We're in the animation, baby!" ); - }); + }, "slow", function() { + $( "#title" ).html( "We're in the callback, baby!" ); + } ); ``` -As I said though, these methods come in pairs, so anything you add using `.queue()`, you need to dequeue to allow the process to continue. In the code above, if I chained more animations on, until I call `$( this ).dequeue()`, the subsequent animations wouldn't run: +## Queues As Callbacks + +Instead of passing a callback as an argument, we can add another function to the *queue* that will act as our callback. This will execute after all of the steps in the animation have completed. ``` $( ".box" ) - .animate({ + .animate( { height: 20 - }, "slow" ) - .queue(function() { + }, "slow") + .queue( function() { $( "#title" ).html( "We're in the animation, baby!" ); + + // This tells jQuery to continue to the next item in the queue $( this ).dequeue(); - }).animate({ - height: 150 - }); + } ); + ``` -Keeping in mind that the animation won't continue until we've explicitly called `.dequeue()`, we can easily create a pausing plugin, by adding a step in the queue that sets a timer and triggers after `delay` milliseconds, at which time, it dequeues the element: +In this example, the queued function will execute right after the animation. + +jQuery does not have any insight into how the queue items function, so we need to call `.dequeue()`, which tells jQuery when to move to the next item in the queue. +Another way of *dequeuing* is by calling the function that is passed to your callback. That function will automatically call `.dequeue()` for you. + +``` +.queue( function( next ) { + console.log( "I fired!" ); + next(); +} ); ``` -$.fn.pause = function( delay ) { - return this.queue(function() { - var elem = this; - setTimeout(function() { - return $( elem ).dequeue(); - }, delay ); - }); -}; +## Custom Queues + +Up to this point all of our animation and queue examples have been using the default queue name which is `fx`. Elements can have multiple queues attached to them, and we can give each of these queues a different name. We can specify a custom queue name as the first argument to the `.queue()` method. + +``` $( ".box" ) - .animate({ - height: 20 - }, "slow" ) - .pause( 1000 ) - .animate({ - height: 150 - }); + .queue( "steps", function( next ) { + console.log( "Step 1" ); + next(); + } ) + .queue( "steps", function( next ) { + console.log( "Step 2" ); + next(); + } ) + .dequeue( "steps" ); +``` + +Notice that we have to call the `.dequeue()` method passing it the name of our custom queue to start the execution. Every queue except for the default, `fx`, has to be manually kicked off by calling `.dequeue()` and passing it the name of the queue. + +## Clearing The Queue + +Since queues are just a set of ordered operations, our application may have some logic in place that needs to prevent the remaining queue entries from executing. We can do this by calling the `.clearQueue()` method, which will empty the queue. + +``` +$( ".box" ) + .queue( "steps", function( next ) { + console.log( "Will never log because we clear the queue" ); + next(); + } ) + .clearQueue( "steps" ) + .dequeue( "steps" ); +``` + +In this example, nothing will happen as we removed everything from the `steps` queue. + +Another way of clearing the queue is to call `.stop( true )`. That will stop the currently running animations and will clear the queue. + +## Replacing The Queue + +When you pass an array of functions as second argument to `.queue()`, that array will replace the queue. + +``` +$( ".box" ) + .queue( "steps", function( next ) { + console.log( "I will never fire as we totally replace the queue" ); + next(); + } ) + .queue( "steps", [ + function( next ) { + console.log( "I fired!" ); + next(); + } + ] ) + .dequeue( "steps" ); +``` + +You can also call `.queue()` without passing it functions, which will return the queue of that element as an array. + ``` +$( ".box" ).queue( "steps", function( next ) { + console.log( "I fired!" ); + next(); +} ); -Remember that the first argument for `.queue()` and `.dequeue()` is `fx`, and that in all of these examples I'm not including it because jQuery sets the argument to `fx` by default — so I don't have to specify it. +console.log( $( ".box" ).queue( "steps" ) ); + +$( ".box" ).dequeue( "steps" ); +``` diff --git a/page/effects/uses-of-queue-and-dequeue.md b/page/effects/uses-of-queue-and-dequeue.md deleted file mode 100644 index edc04b98..00000000 --- a/page/effects/uses-of-queue-and-dequeue.md +++ /dev/null @@ -1,214 +0,0 @@ - - -Queues in jQuery are used for animations. You can use them for any purpose you like. They are an array of functions stored on a per element basis, using `jQuery.data()`. They are First In, First Out (FIFO). You can add a function to the queue by calling `.queue()`, and you remove (by calling) the functions using `.dequeue()`. - -To understand the internal jQuery queue functions, reading the source and looking at examples helps me out tremendously. One of the best examples of a queue function I've seen is `.delay()`: - -``` -$.fn.delay = function( time, type ) { - time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time; - type = type || "fx"; - - return this.queue( type, function( next, hooks ) { - var timeout = setTimeout( next, time ); - hooks.stop = function() { - clearTimeout( timeout ); - }; - }); -}; -``` - -## The default queue – fx - -The default queue in jQuery is `fx`. The default queue has some special properties that are not shared with other queues. - -* Auto Start: When calling `$(elem).queue( function() {} );` the fx queue will automatically dequeue the next function and run it if the queue hasn't started. -* "inprogress" sentinel: Whenever you `dequeue()` a function from the fx queue, it will `unshift()` (push into the first location of the array) the string "inprogress" — which flags that the queue is currently being run. -* It's the default! The fx queue is used by `.animate()` and all functions that call it by default. - -**Note:** If you are using a custom queue, you must manually `.dequeue()` the functions, they will not auto start! - -## Retrieving/Setting the queue - -You can retrieve a reference to a jQuery queue by calling `.queue()` without a function argument. You can use the method if you want to see how many items are in the queue. You can use `push`, `pop`, `unshift`, and `shift` to manipulate the queue in place. You can replace the entire queue by passing an array to the `.queue()` function. - -## Quick Examples: - -``` -// Assume elem is a jQuery object that contains an element we are animating -var queue = elem.queue(); - -// Remove the last function from the animation queue -var lastFunc = queue.pop(); - -// Insert it at the beginning -queue.unshift( lastFunc ); - -// Replace queue with the first three items in the queue -elem.queue( queue.slice( 0, 3 ) ); -``` - -### An animation (fx) queue example: - -``` -$(function() { - - // Let's do something with Google Maps - var canvas = $( "#map_canvas" ); - - var latlng = new google.maps.LatLng( -34.397, 150.644 ); - - var options = { - zoom: 8, - center: latlng, - mapTypeId: google.maps.MapTypeId.ROADMAP - }; - - var geocoder = new google.maps.Geocoder(); - - var map = new google.maps.Map( canvas[0], options ); - - var resized = function() { - - // Simple animation callback - let maps know we resized - google.maps.event.trigger( map, "resize" ); - }; - - // Wait for two seconds - canvas.delay( 2000 ); - - // Resize the div - canvas.animate({ - width: 250, - height: 250, - marginLeft: 250, - marginTop:250 - }, resized ); - - // Geocode something - canvas.queue(function( next ) { - - // Find Stack Overflow's whois address - geocoder.geocode( { - address: "55 Broadway New York NY 10006" - }, handleResponse ); - - function handleResponse( results, status ) { - if ( status === google.maps.GeocoderStatus.OK ) { - var location = results[ 0 ].geometry.location; - map.setZoom( 13 ); - map.setCenter( location ); - new google.maps.Marker({ - map: map, - position: location - }); - } - - // Geocoder result returned, continue with animations - next(); - } - }); - - // After we find Stack Overflow, wait 3 more seconds - canvas.delay( 3000 ); - - // Then resize the map again - canvas.animate({ - width: 500, - height: 500, - marginLeft:0, - marginTop: 0 - }, resized ); -}); -``` - -### Queueing something like Ajax Calls: - -``` -// jQuery on an empty object, we are going to use this as our queue -var ajaxQueue = $({}); - -$.ajaxQueue = function( ajaxOpts ) { - - // Hold the original complete function - var oldComplete = ajaxOpts.complete; - - // Queue our ajax request - ajaxQueue.queue(function( next ) { - - // Create a complete callback to invoke the next event in the queue - ajaxOpts.complete = function() { - - // Invoke the original complete if it was there - if ( oldComplete ) { - oldComplete.apply( this, arguments ); - } - - // Run the next query in the queue - next(); - }; - - // Run the query - $.ajax( ajaxOpts ); - }); -}; - -// Get each item we want to copy -$( "#items li" ).each(function( idx ) { - - // Queue up an ajax request - $.ajaxQueue({ - url: "/ajax_html_echo/", - data: { - html: "[" + idx + "] " + $( this ).html() - }, - type: "POST", - success: function( data ) { - - // Write to #output - $( "#output" ).append( $( "
  • ", { - html: data - })); - } - }); -}); -``` - -### Another custom queue example - -``` -// jQuery on an empty object - a perfect queue holder -var theQueue = $({}); - -$.each([ 1, 2, 3 ], function( i, num ) { - - // Add some really simple functions to a queue - theQueue.queue( "alerts", function( next ) { - - // Show something, and if the user clicks "yes", run the next function - if ( confirm( "index: " + i + " = " + num + "\nRun the next function?" ) ) { - next(); - } - }); -}); - -// Create a button to run the queue -$( "