Using jQuery.noConflict() instead of jQuery.noConflict(true) in contrib.admin

512 views
Skip to first unread message

tyrion-mx

unread,
Oct 22, 2010, 1:09:11 PM10/22/10
to Django developers
1) contrib.admin places jQuery in its own namespace `django.jQuery`.
In this way other jQuery instances should not conflict with it.
2) It also removes the dollar sign AND the `jQuery` object from the
global scope.

*I think* removing the `jQuery` object is not necessary because it
*should* not conflict with any other jQuery instance.

If an admin customization that uses jQuery is loaded, as it should,
after the contrib.admin's javascript, its `jQuery` object will
override the django's one, and django will still be able to use jQuery
with `django.jQuery`.

If an admin customization is loaded before the contrib.admin's
javascript, it *should not* work anyway even if we removed jQuery from
the global scope. That's because jQuery.noConflict(true) removes the
jQuery object from the global scope, but doesn't prevent it to be
created and attached to window (thus overwriting the user's one).

Moreover I wont' be able to use any jQuery plugin (that directly
references `jQuery`) in the admin (without hacking with
ModelAdmin._media), because the `jQuery` object does not exist. I am
forced to include jquery twice ...

Rob Hudson

unread,
Oct 22, 2010, 4:27:47 PM10/22/10
to django-d...@googlegroups.com
On Fri, Oct 22, 2010 at 10:09 AM, tyrion-mx <tyri...@gmail.com> wrote:
> 1) contrib.admin places jQuery in its own namespace `django.jQuery`.
> In this way other jQuery instances should not conflict with it.
> 2) It also removes the dollar sign AND the `jQuery` object from the
> global scope.
>
> *I think* removing the `jQuery` object is not necessary because it
> *should* not conflict with any other jQuery instance.

I don't think of it as "removing" the object... it's more of putting
back what was there before Django's jQuery initialization happened.

> If an admin customization that uses jQuery is loaded, as it should,
> after the contrib.admin's javascript, its `jQuery` object will
> override the django's one, and django will still be able to use jQuery
> with `django.jQuery`.

I like that there is no ambiguity for Django admin javascript writers
on whether they should extend or use window.jQuery or django.jQuery.

> If an admin customization is loaded before the contrib.admin's
> javascript, it *should not* work anyway even if we removed jQuery from
> the global scope. That's because jQuery.noConflict(true) removes the
> jQuery object from the global scope, but doesn't prevent it to be
> created and attached to window (thus overwriting the user's one).

I believe this isn't quite right. If I load my own jQuery (and
plugins that possibly may extend that specific jQuery object) prior to
admin loading its jQuery, the admin's jQuery will move the existing
window.jQuery to a temp variable, load itself, then put the original
object back. Thus we have the original jQuery unaffected and lives in
window.jQuery (along with all its extensions or different version),
and Django's jQuery lives at django.jQuery.

With `jQuery.noConflict(true)` we're not overwriting the `$` or
`jQuery` global objects at all, and keeping our own jQuery self
contained.

> Moreover I wont' be able to use any jQuery plugin (that directly
> references `jQuery`) in the admin (without hacking with
> ModelAdmin._media), because the `jQuery` object does not exist. I am
> forced to include jquery twice ...

This is a good point...

I suppose one could assign Django's jQuery object to the global jQuery
object? I haven't tried it but this might avoid needing to include 2
copies of jQuery if you're ok with the version Django bundles:

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


-Rob

Chuck Harmston

unread,
Oct 22, 2010, 4:37:09 PM10/22/10
to django-d...@googlegroups.com
A good 

Moreover I wont' be able to use any jQuery plugin (that directly
references `jQuery`) in the admin (without hacking with
ModelAdmin._media), because the `jQuery` object does not exist. I am
forced to include jquery twice ...

Per the jQuery docs, plugins should *not* directly reference the jQuery object; they should do it in a scope-controlled closure executed at creation with jQuery passed to it as a parameter. This way, plugins can safely use the $ shortcut without worrying about whether or not noConflict mode is on, whether it is assigned to a separate namespace (like django.jQuery), etc; you simply need to change the parameter passed to the closure. In the case of django.jQuery, it should look like this:

(function( $ ){
    $.fn.myPlugin = function() {
        this.each(function() {
            this.doSomething();
        });
    };
})( django.jQuery );

- CH

tyrion-mx

unread,
Oct 23, 2010, 9:03:01 AM10/23/10
to Django developers


On Oct 22, 10:37 pm, Chuck Harmston <ch...@chuckharmston.com> wrote:
> Per the jQuery docs <http://docs.jquery.com/Plugins/Authoring>, plugins
> should *not* directly reference the jQuery object; they should do it in a
> scope-controlled closure executed at creation with jQuery passed to it as a
> parameter. This way, plugins can safely use the $ shortcut without worrying
> about whether or not noConflict mode is on, whether it is assigned to a
> separate namespace (like django.jQuery), etc; you simply need to change the
> parameter passed to the closure. In the case of django.jQuery, it should
> look like this:
>
> (function( $ ){
>     $.fn.myPlugin = function() {
>         this.each(function() {
>             this.doSomething();
>         });
>     };
>
> })( django.jQuery );
>

I know this, but that's not the point. I could change "jQuery" to
"django.jQuery" for my own jquery plugins, but then I will be forced
to duplicate the plugin file: one using "django.jQuery" for the admin
and an other using "jQuery" for the rest of the site. And that's not
good ...
In addiction, I don't want to edit jQuery UI, and to make it work
without loading an other instance of jquery I *must* load it before
jquery.init.js (that calls noConflict(true)).

Owen Nelson

unread,
Oct 26, 2010, 12:35:38 AM10/26/10
to django-d...@googlegroups.com
I think this was hinted at, but this should work for any plugins that are violating the best practice of using a closure, and those that don't.
No need to duplicate your plugins, just "alias" the library.

<script type="text/javascript>
var jQuery = django.jQuery;
</script>
<script src="/static/my_fragile_plugin.js" type="text/javascript"></script>

One other thing to keep in mind is that if you're specifically targeting django admin with your code, it might just be worth the effort to set the references in your closures to django.jQuery.  If need be, you could wrap your closures in a function that takes a reference to the jQuery object you want to bind to and do something like:

<script src="/static/my_fragile_plugin.js" type="text/javascript"></script>
<script type="text/javascript">
my_fragile_plugin.init(django.jQuery);
</script>

Make sense?

Owen Nelson




--
You received this message because you are subscribed to the Google Groups "Django developers" group.
To post to this group, send email to django-d...@googlegroups.com.
To unsubscribe from this group, send email to django-develop...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/django-developers?hl=en.


Reply all
Reply to author
Forward
0 new messages