To allow developers to identify and fix compatibility issues when migrating older jQuery code, the development (uncompressed) version of the plugin generates console warning messages whenever any of its functionality is called. The messages only appear once on the console for each unique message.
In most cases these messages are simply warnings; code should continue to work properly with later versions of jQuery as long as the jQuery Migrate plugin is used, but we recommend changing the code where possible to eliminate warnings so that the plugin does not need to be used.
The production (compressed) version of the plugin does not generate these warnings. To continue using jQuery code that has compatibility issues without making any changes and without console messages, simply include the production version in the file rather than the development version. See the README for download instructions.
All warnings generated by this plugin start with the text "JQMIGRATE" for easy identification. The warning messages, causes, and remediation instructions are listed below.
This is not a warning, but a console log message the plugin shows when it first loads to indicate whether warnings will be shown on the console when appropriate. As of version 1.4.0 this message is also shown with production builds. The use jQuery Migrate in production has performance impacts and can complicate debugging as it modifies the normal behavior of the version of jQuery being used.
Cause: Prior to jQuery 1.8, the undocumented jQuery.attrFn
object provided a list of properties supported by the $(html, props)
method. It is no longer required as of jQuery 1.8, but some developers "discovered" it by reading the source and began to use it. Their code still expects jQuery.attrFn
to be present, attempts to assign values to it, and will throw errors if it is not present.
Solution: Ensure that you are using the latest version of jQuery UI (1.8.21 or later) and jQuery Mobile (1.2.1 or later); they no longer use jQuery.attrFn
. Examine any third-party plugins for the string attrFn
and report its use to the plugin authors (not to jQuery team).
Cause: In jQuery 1.9, HTML strings passed to $()
must start with a tag; in other words the first character of the string must be a <
character. There cannot be any preceding characters, including whitespace. This is done to reduce the chances of inadvertent execution of scripts that might be present in HTML that is obtained from the URL, AJAX, or other sources. Use of simple literal HTML strings like $("<div />")
or $("<p>hello</p>")
are unaffected since they should not have leading spaces or text.
Solution: Use the $.parseHTML()
method to parse arbitrary HTML, especially HTML from external sources. To obtain a jQuery object that has the parsed HTML without running scripts, use $($.parseHTML("string"))
. To run scripts in the HTML as well, use $($.parseHTML("string", document, true))
instead. We do not recommend running $.trim()
on the string to circumvent this check.
Cause: HTML strings passed to $()
should begin and end with tags. Any text following the last tag is ignored. When upgrading to jQuery 1.9 and using $.parseHTML()
, note that leading or trailing text is not ignored, and those text nodes will be part of the data returned.
Solution: Usually this warning is due to an error in the HTML string, where text is present when it should not be there. Remove the leading or trailing text before passing the string to $.parseHTML()
if it should not be part of the collection. Alternatively you can use $($.parseHTML(html)).filter("*")
to remove all top-level text nodes from the set and leave only elements.
Cause: Selectors such as a[href=#main]
are not valid CSS syntax because the value contains special characters that are not quoted. Until jQuery 1.11.3/2.1.4 this was accepted, but the behavior is non-standard and was never documented. In later versions this selector throws an error. In some cases with complex selectors, Migrate may not attempt a repair. In those cases a fatal error will be logged on the console and you will need to fix the selector manually.
Solution: Put quotes around any attribute values that have special characters, e.g. a[href="#main"]
. The warning message contains the selector that caused the problem, use that to find the selector in the source files.
Cause: IE 6, 7, and 8 throw an error if you attempt to change the type attribute of an input or button element, for example to change a radio button to a checkbox. Prior to 1.9, jQuery threw an error for every browser to create consistent behavior. As of jQuery 1.9 setting the type is allowed, but will still throw an error in oldIE.
Solution: For compatibility with oldIE, do not attempt to change the type of an input element. Instead, create a new element in your code and replace the old one.
Cause: A browser runs in "quirks mode" when the HTML document does not have a <!doctype ...>
as its first non-blank line, or when the doctype in the file is invalid. This mode causes the browser to emulate 1990s-era (HTML3) behavior. In Internet Explorer, it also causes many high-performance APIs to be hidden in order to better emulate ancient browsers. jQuery has never been compatible with, or tested in, quirks mode.
Solution: Put a valid doctype in the document and ensure that the document is rendering in standards mode. The simplest valid doctype is the HTML5 one, which we highly recommend: <!doctype html>
. The jQuery Migrate plugin does not attempt to fix issues related to quirks mode.
Cause: These two deprecated properties are false
when the page is using Quirks mode, and true
when the page is in standards mode. Quirks mode was never supported in jQuery so these properties were removed.
Solution: Do not use jQuery in Quirks mode, it has never been supported. See the previous item for solutions.
Cause: Before jQuery 1.9.0, the $.parseJSON()
method allowed some invalid JSON strings and returned null
as a result without throwing an error. This put it at odds with the JSON.parse()
method. The two methods are aligned as of 1.9.0 and values such as an empty string are properly not considered valid by $.parseJSON()
.
Solution: If you want to consider values such as ""
or false
successful and treat them as null
, check for them before calling $.parseJSON()
. Since falsy values such as an empty string were previously returned as a null
without complaint, this code will suffice in most cases:
var json = $.parseJSON(jsonString || "null");
If your own code is not calling $.parseJSON()
directly, it is probably using AJAX to retrieve a JSON value from a server that is returning an empty string in the content body rather than a valid JSON response such as null
or {}
. If it isn't possible to correct the invalid JSON in the server response, you can retrieve the response as text:
$.ajax({
url: "...",
dataType: "text",
success: function( text ) {
var json = text? $.parseJSON(text) : null;
...
}
});
Cause: jQuery.browser
was deprecated in version 1.3, and finally removed in 1.9. Browser sniffing is notoriously unreliable as means of detecting whether to implement particular features.
Solution: Where possible, use feature detection to make code decisions rather than trying to detect a specific browser. The Modernizr library provides a wide variety of feature detections. As a last resort, you can directly look at the navigator.userAgent
string to detect specific strings returned by the browser.
Cause: The jQuery.sub()
method provided an imperfect way for a plugin to isolate itself from changes to the jQuery
object. Due to its shortcomings, it was deprecated in version 1.8 and removed in 1.9.
Solution: Rewrite the code that depends on jQuery.sub()
, use the minified production version of the jQuery Migrate plugin to provide the functionality, or extract the jQuery.sub()
method from the plugin's source and use it in the application.
Cause: Until jQuery 1.9, the string "hover" was allowed as an alias for the string "mouseenter mouseleave" when attaching an event handler. This unusual exception provided no real benefit and prevented the use of the name "hover" as a triggered event. Note: This is not related to the .hover()
method, which has not been deprecated.
Solution: Replace use of the string "hover" with "mouseenter mouseleave" within any .on()
, .bind()
, .delegate()
, or .live()
event binding method.
Cause: The $().error()
method was used to attach an "error" event to an element but has been removed in 1.9 to reduce confusion with the $.error()
method which is unrelated and has not been deprecated. It also serves to discourage the temptation to use $(window).error()
which does not work because window.onerror
does not follow standard event handler conventions.
Solution: Change any use of $().error(fn)
to $().on("error", fn)
.
Cause: The .load()
and .unload()
event methods attach a "load" and "unload" event, respectively, to an element. They were deprecated in 1.9 to reduce confusion with the AJAX-related .load()
method that loads HTML fragments and which has not been deprecated. Note that these two methods are used almost exclusively with a jQuery collection consisting of only the window
element. Also note that attaching an "unload" or "beforeunload" event on a window via any means can impact performance on some browsers because it disables the document cache (bfcache). For that reason we strongly advise against it.
Solution: Change any use of $().load(fn)
to $().on("load", fn)
and $().unload(fn)
to $().on("unload", fn)
.
Cause: There are two completely different meanings for the .toggle()
method. The use of .toggle()
to show or hide elements is not affected. The use of .toggle()
as a specialized click handler was deprecated in 1.8 and removed in 1.9.
Solution: Rewrite the code that depends on $().toggle()
, use the minified production version of the jQuery Migrate plugin to provide the functionality, or extract the $().toggle()
method from the plugin's source and use it in the application.
Cause: The .live()
and .die()
methods were deprecated in 1.7 due to their performance and usability drawbacks, and are no longer supported.
Solution: Rewrite calls to .live()
using .on()
or .delegate()
. Instructions for doing so are provided in the .live()
API documentation.
Cause: As of jQuery 1.9, the global AJAX events (ajaxStart, ajaxStop, ajaxSend, ajaxComplete, ajaxError, and ajaxSuccess) are only triggered on the document
element.
Solution: Change the program to listen for the AJAX events on the document. For example, if the code currently looks like this:
$("#status").ajaxStart(function(){ $(this).text("Ajax started"); });
Change it to this:
$(document).ajaxStart(function(){ $("#status").text("Ajax started"); });
Cause: jQuery 1.9 does not support globally triggered events. The only documented global events were the AJAX events and they are now triggered only on document
as discussed above. jQuery never provided a documented interface for outside code to trigger global events.
Solution: Change the program to avoid the use of global events. The jQuery Migrate plugin warns about this case but does not restore the previous behavior since it was undocumented.
Cause: jQuery.event.handle
was never documented, and deprecated with jQuery 1.7 (see http://forum.jquery.com/topic/deprecated-event-properties-used-in-jquery). As of jQuery 1.9, it has been removed.
Solution: Use documented jQuery APIs, such as .trigger
.
Cause: Prior to jQuery 1.9, $().attr("value")
retrieved the value property instead of the value attribute (which generally reflects the value that was read from HTML markup). This caused inconsistent behavior with selectors referencing the value attribute.
Solution: Use $().val()
(for form controls) or $().prop("value")
(for other elements) to get the current value, and try to explicitly limit the use of [value=…]
in selectors to input
and/or option
elements wherever possible.
Cause: Prior to jQuery 1.9, $().attr( "value", val )
set the value property instead of the value attribute. This caused inconsistent behavior with selectors referencing the value attribute.
Solution: Use $().val( val )
(for form controls) or $().prop( "value", val )
(for other elements) to set the current value.
Cause: Prior to jQuery 1.9, $().attr("checked")
etc. would sometimes use the checked|selected property instead of the attribute when interacting with non-XML elements, despite the fact that browsers and the HTML specifications allow the properties (current state) to differ from the attributes (initial/default state). This was a holdover from earlier versions of jQuery that did not offer $().prop
.
Solution: Boolean properties should generally not be passed to $().attr
at all; replace with $().prop
unless you truly intend to update the underlying HTML attribute.
Cause: The .pipe()
method on a jQuery.Deferred
object was deprecated as of jQuery 1.8, when the .then()
method was changed to perform the same function.
Solution: In most cases it is sufficient to change all occurrences of .pipe()
to .then()
. Ensure that you aren't relying on context/state propagation (e.g., using this
) or synchronous callback invocation, which were dropped from .then()
for Promises/A+ interoperability as of jQuery 3.0.
Cause: As of jQuery 1.7, the isResolved()
and isRejected
methods of the jQuery.Deferred
object have been deprecated. They were removed in jQuery 1.8 and are no longer available in later versions.
Solution: To determine the state of a Deferred object, call deferred.state()
and check for a "resolved"
or "rejected"
string values.
Cause: jQuery.buildFragment()
and jQuery.clean()
are undocumented internal methods. The signature of jQuery.buildFragment()
was changed in jQuery 1.8 and 1.9, and jQuery.clean()
was removed in 1.9. However, we are aware of some plugins or other code that might be using them.
Solution: Rewrite any code that makes use of these or any other undocumented methods. For example the jQuery.parseHTML()
method, introduced in jQuery 1.8, can convert HTML to an array of DOM elements that you can append to a document fragment.
Cause: Prior to 1.9, .data("events")
could be used to retrieve jQuery's undocumented internal event data structure for an element if no other code had defined a data element with the name "events". This special case has been removed in 1.9.
Solution: There is no public interface to retrieve this internal data structure, and it remains undocumented. The only useful applications might be for debugging. The data is available via jQuery._data("events")
but this is not a documented interface.
Cause: Some pages unwisely use code similar to $(location.hash)
in order to select what they think is going to be an ID value encoded on the page. However, an attacker can create a cross-site scripting (XSS) injection by using a string similar to #<script>...</script>
and run code to steal user data. The Migrate plugin does not allow a string of this form to be used.
Solution: If you are creating HTML that absolutely requires leading text, use $.parseHTML
and pass the results to $()
.
Cause: The .andSelf()
method has been renamed to .addBack()
as of jQuery 1.9 to better reflect its purpose of adding back the previous set of results.
Solution: Replace any use of .andSelf()
with .addBack()
.
Cause: The .size()
method returns the number of elements in the current jQuery object, but duplicates the more-efficient .length
property which provides the same functionality. As of jQuery 1.9 the .length
property is the preferred way to retrieve this value.
Solution: Replace any use of .size()
with .length
.
Cause: The jQuery.swap()
method temporarily exchanges a set of CSS properties. It was never documented as part of jQuery's public API and should not be used because it can cause performance problems due to forced layout.
Solution: Rework the code to avoid calling jQuery.swap()
, or explicitly set and restore the properties you need to change.
Cause: Using one of jQuery's API methods to bind a "ready" event, e.g. $( document ).on( "ready", fn )
, will cause the function to be called when the document is ready, but only if it is attached before the browser fires its own DOMContentLoaded
event. That makes it unreliable for many uses, particularly ones where jQuery or its plugins are loaded asynchronously after page load.
Solution: Replace any use of $( document ).on( "ready", fn )
with $( document ).ready( fn )
or more simply, just $( fn )
. These alternative methods work reliably even when the document is already loaded.