Danny W. Adair
Danny W. Adair

Reputation: 12968

How to provide $ to third-party, external jQuery plugins in Django admin

I've included a couple of third-party jQuery plugins in my Django admin base template which assume "$" to be available.

For my own code, I've always been happy to just do

(function($) {
    my_code = 'here';
})(django.jQuery);

but how can I provide "$" to other people's code which sits in external files?

<script src="{{ STATIC_URL }}js/jquery.json-2.2.min.js" type="text/javascript"></script>

complains that "$" is undefined. I've tried to put

<script type="text/javascript">var $ = django.jQuery;</script>

before that external reference, but to no avail (btw, why is that? I understand loading happens concurrently, but execution? I can use that "$" immediately after defining it.).

I'm happy with the jQuery version that Django admin provides and really don't want to load another one. I also don't want to edit someone else's plugin so that it starts with the above "$" re-definition. EDIT: Neither do I want to wrap it like my own code, I just don't want to touch those files at all.

Do I really have to resort to putting $.getScript() - http://api.jquery.com/jQuery.getScript - into my anonymous function to load such files?

EDIT: After actually looking into that external file jquery.json-2.2.min.js, I saw it was already wrapped into a function that assumed "jQuery" to be available, rather than "$". After inserting

var jQuery = django.jQuery;

before the external reference, it worked fine. But is this really how this should be done?

Upvotes: 12

Views: 3548

Answers (4)

benzkji
benzkji

Reputation: 1867

There is a solution that works without double loading of jQuery, and without hacking jquery.init.js. It relies on the order the libraries are loaded in the admin.

Idea

  1. load jquery
  2. load third party libraries that depend on jQuery/$
  3. optional, load your own scripts, that use jQuery/$
  4. load jquery.init.js from Django (does the django.jQuery and noConflict thing)
  5. optional, load your own scripts, that use django.jQuery

Example

Media Attribute of an Admin, including select2.js.

    class Media:
        js = [
            'admin/js/vendor/jquery/jquery.js',
            'admin/js/vendor/select2/select2.full.js',
            'your_own/js/your_own-using-django.jQuery.js',            
            'admin/js/jquery.init.js',
            'your_own/js/your_own-using-django.jQuery.js',
        ]

Upvotes: 1

Philipp Zedler
Philipp Zedler

Reputation: 1670

Override django's staticfile admin/js/jquery.init.js by creating a file with the same name and path in your app's staticfiles directory.

The original content is this

/* Puts the included jQuery into our own namespace using noConflict and passing
 * it 'true'. This ensures that the included jQuery doesn't pollute the global
 * namespace (i.e. this preserves pre-existing values for both window.$ and
 * window.jQuery).
 */
var django = {
    "jQuery": jQuery.noConflict(true)
};

Just remove the .noConflict(true).

Upvotes: 6

Simon Steinberger
Simon Steinberger

Reputation: 6825

For third party plugins, it's usually best to load your own copy of jQuery before including the other plugins. For Django 1.4+ this may look like so in your corresponding admin.py file:

class Media:
    js = (
        'http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js',
        '/static/js/third_party_plugin.js',
    )

If your plugins do not depend on a recent version of jQuery, you may also use Django's included version by defining $ and jQuery at the top of your plugin:

var jQuery = django.jQuery, $ = jQuery;

As of version 1.6, Django will ship with jQuery 1.9.1. Before that, jQuery 1.4 is used, which does not work for a lot of new/updated plugins.

Upvotes: 1

Black Box Operations
Black Box Operations

Reputation: 257

Yeah, I remember this problem. I feel your pain.

A great workaround is to restructure your js files in such a way that Django can read them as URLs. In your URLs file, add the pattern below:

urlpatterns = patterns((r"^js(?:/(?P<type>\w+))?", "app.views.render_js"))

Now, in your init.py, add the following code:

JS_FILES = {"name" : "name.js",
            "thing" : "thing.js"};

def render_main_js(req, type = None) :
    return render_to_response(JS_FILES.get(type, "main.js"), mimetype="text/javascript");

Once the code is in place and assuming you have your javascript files in /js/* you can include your javascript by using the code below:

<script type="text/javascript" src="/js/name"></script>
<script type="text/javascript" src="/js/thing"></script>

Upvotes: 1

Related Questions