Jordan Reiter
Jordan Reiter

Reputation: 21002

jQuery plugin becomes undefined when called from within $.get

I'm using jQuery TokenInput and there's a place in my code where I'd like to do an Ajax call prior to actually calling TokenInput. However, if I try to call TokenInput from within $.get I get

Uncaught TypeError: Object #<Object> has no method 'tokenInput'

So this works:

$("#myfield").tokenInput('/search/', {
    tokenLimit: 3
});
$("#myfield").tokenInput("add", { id: 100, name: "Fake Data" });

But this doesn't work:

var old_value = $("#myfield").val();
$("#myfield").tokenInput('/search/', {
    tokenLimit: 3
});
$.get('/search/', { q: old_value }, function (data) {
    record = data[0];
    $("#myfield").tokenInput("add", {id: record.id, name: record.name });
});

So I guess what I'm wondering is, what happened to $.tokenInput? Is there something I can do to ensure it's available from within $.get?

Source code for jQuery.TokenInput: https://github.com/loopj/jquery-tokeninput/blob/master/src/jquery.tokeninput.js

Update

Oh horsefeathers. Looking at the code I see that another section of code (in this case, from django-cms) is pulling in a different version of jQuery. This is not as a result of my $.get request, it's just on another part of the page.

Here's what I don't get, though: why does it work in one context but not the other? Both jQuery versions are already loaded by the time we get to the $.tokenInput code. So what is happening to $ so that it retains .tokenInput?

Also, I thought that there was a way to have two versions of jQuery on a single page and not run into problems -- that one version of jQuery will somehow "preserve" the other version. Obviously it's able to do it partially, since $.tokenInput does work some of the time.

Fortunately on this page I was able to just disable the module that calls the other jQuery, but I won't always be able to. What steps can I take to deal with this situation, given that I cannot avoid having two versions on the page? (django-cms is only compatible with an older version of jQuery. Very annoying, but nothing I can do about it).

Upvotes: 3

Views: 1189

Answers (2)

Jan Święcki
Jan Święcki

Reputation: 1683

Relative to the problem.

This is not a direct anwser to the question, but general fact about killing jQuery plugins. I've had a problem as described below and after googling it I ended up here, so maybe someone will too.

Appending <script /> tags to the document will execute these scripts and possibly kill all your plugins inside $.

Harmful script:

// Here html response has full index.php body,
// i.e. html has <body /> and <script /> tags inside
// (including `<script src="js/jquery.js">`).
$.get(url).done(function(html)
{
    // Here happens redeclaration of jQuery variable (i.e. $ variable),
    // because of `<script src="js/jquery.js">` inside `<body />`.
    // 
    // Redeclaration of jQuery variable mean
    // that all plugins will die (i.e. all
    // not native jQuery attributes become undefined).
    $(html).appendTo("body");
});

edit:

Another example:

$("<html />").html("<script src='js/jquery.js'></script>");

will load jquery.js.

Thing to note: scripts injected like this will be loaded via ajax (i.e. XMLHttpRequest).

Note: all of this was tested in Chrome, but jQuery behaviour regarding html parsing is not cross-browser:

"When passing in complex HTML, some browsers may not generate a DOM that exactly replicates the HTML source provided. As mentioned, we use the browser's .innerHTML property to parse the passed HTML and insert it into the current document. During this process, some browsers filter out certain elements such as <html>, <title>, or <head> elements. As a result, the elements inserted may not be representative of the original string passed."

source

Upvotes: 2

JAAulde
JAAulde

Reputation: 19560

I suspect the script blocks in which it is working are above the script element which loads in the second copy. So they run just fine--until you drop something into an async method like an AJAX call back. By the time that fires, the later script blocks have executed, removing the support needed in the callback

See example: http://jsfiddle.net/RukeN/1/

Upvotes: 1

Related Questions