From eb8623b8da76aa323381eca9589706e8a71e165e Mon Sep 17 00:00:00 2001 From: Arthur Verschaeve Date: Sun, 1 Mar 2015 10:16:03 +0100 Subject: [PATCH 1/3] Effects: Merge 2 articles on queues --- order.json | 3 +- page/effects/queue-and-dequeue-explained.md | 140 ++++++++++--- page/effects/uses-of-queue-and-dequeue.md | 214 -------------------- 3 files changed, 112 insertions(+), 245 deletions(-) delete mode 100644 page/effects/uses-of-queue-and-dequeue.md 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..64ed1294 100644 --- a/page/effects/queue-and-dequeue-explained.md +++ b/page/effects/queue-and-dequeue-explained.md @@ -4,53 +4,135 @@ "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() { + }, "slow", function() { $( "#title" ).html( "We're in the animation, 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 ).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: +To add multiple functions to the queue, you can call `.queue()` multiple times. ``` -$.fn.pause = function( delay ) { - return this.queue(function() { - var elem = this; - setTimeout(function() { - return $( elem ).dequeue(); - }, delay ); - }); -}; - $( ".box" ) - .animate({ + .animate( { height: 20 }, "slow" ) - .pause( 1000 ) - .animate({ - height: 150 - }); + .queue( function() { + console.log('I fired!'); + } ) + .animate( { + height: 50 + }, "fast" ) + .queue( function() { + console.log('I fired too!'); + } ); +``` + +If you ran this example, you will have seen that the last animation never runs and the last callback doesn't fire. This is because we basically never told jQuery to continue. Inside of the first queued function, you will need to call `.dequeue()` to move forward to the next function in the queue. + +``` +.queue( function() { + console.log('I fired!'); + $( this ).dequeue(); +} ) +``` + +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(); +} ) +``` + +## 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" ) + .queue( "steps", function( next ) { + console.log( "Step 1" ); + next(); + } ) + .queue( "steps", function( next ) { + console.log( "Step 2" ); + next(); + } ) + .dequeue( "steps" ); ``` -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. +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( "I fired" ); + 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 won't fire" ); + 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(); +} ); + +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 -$( "