0

I am having trouble because of django's app, that is smart select, it tries to load jquery by itself. I am already loading jquery by myself in head and after that I am loading JQuery UI related stuff. But as smartselect come in body it also load jquery again that cause problem for UI related stuff. I don't understand how can I stop smartselect jquery if it is already loaded.

Following is the code for widgets.py file of smart select app.

    import django
from django.conf import settings
from django.forms.widgets import Select
from django.contrib.admin.templatetags.admin_static import static
from django.core.urlresolvers import reverse
from django.utils.encoding import iri_to_uri
from django.utils.safestring import mark_safe
from django.db.models import get_model
import locale
from smart_selects.utils import unicode_sorter


if django.VERSION >= (1, 2, 0) and getattr(settings,
        'USE_DJANGO_JQUERY', True):
    USE_DJANGO_JQUERY = True
else:
    USE_DJANGO_JQUERY = False
    JQUERY_URL = getattr(settings, 'JQUERY_URL', 'http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js')


class ChainedSelect(Select):
    def __init__(self, app_name, model_name, chain_field, model_field, show_all, auto_choose, manager=None, *args, **kwargs):
        self.app_name = app_name
        self.model_name = model_name
        self.chain_field = chain_field
        self.model_field = model_field
        self.show_all = show_all
        self.auto_choose = auto_choose
        self.manager = manager
        super(Select, self).__init__(*args, **kwargs)

    class Media:
        if USE_DJANGO_JQUERY:
            js = [static('admin/%s' % i) for i in
                  ('js/jquery.min.js', 'js/jquery.init.js')]
        elif JQUERY_URL:
            js = (
                JQUERY_URL,
            )

    def render(self, name, value, attrs=None, choices=()):
        if len(name.split('-')) > 1: # formset
            chain_field = '-'.join(name.split('-')[:-1] + [self.chain_field])
        else:
            chain_field = self.chain_field

        if self.show_all:
            view_name = "chained_filter_all"
        else:
            view_name = "chained_filter"
        kwargs = {'app':self.app_name, 'model':self.model_name, 'field':self.model_field, 'value':"1"}
        if self.manager is not None:
            kwargs.update({'manager': self.manager})
        url = "/".join(reverse(view_name, kwargs=kwargs).split("/")[:-2])
        if self.auto_choose:
            auto_choose = 'true'
        else:
            auto_choose = 'false'
        empty_label = iter(self.choices).next()[1] # Hacky way to getting the correct empty_label from the field instead of a hardcoded '--------'
        js = """
        <script type="text/javascript">
        //<![CDATA[
        (function($) {
            function fireEvent(element,event){
                if (document.createEventObject){
                // dispatch for IE
                var evt = document.createEventObject();
                return element.fireEvent('on'+event,evt)
                }
                else{
                // dispatch for firefox + others
                var evt = document.createEvent("HTMLEvents");
                evt.initEvent(event, true, true ); // event type,bubbling,cancelable
                return !element.dispatchEvent(evt);
                }
            }

            function dismissRelatedLookupPopup(win, chosenId) {
                var name = windowname_to_id(win.name);
                var elem = document.getElementById(name);
                if (elem.className.indexOf('vManyToManyRawIdAdminField') != -1 && elem.value) {
                    elem.value += ',' + chosenId;
                } else {
                    elem.value = chosenId;
                }
                fireEvent(elem, 'change');
                win.close();
            }

            $(document).ready(function(){
                function fill_field(val, init_value){
                    if (!val || val==''){
                        options = '<option value="">%(empty_label)s<'+'/option>';
                        $("#%(id)s").html(options);
                        $('#%(id)s option:first').attr('selected', 'selected');
                        $("#%(id)s").trigger('change');
                        return;
                    }
                    $.getJSON("%(url)s/"+val+"/", function(j){
                        var options = '<option value="">%(empty_label)s<'+'/option>';
                        for (var i = 0; i < j.length; i++) {
                            options += '<option value="' + j[i].value + '">' + j[i].display + '<'+'/option>';
                        }
                        var width = $("#%(id)s").outerWidth();
                        $("#%(id)s").html(options);
                        if (navigator.appVersion.indexOf("MSIE") != -1)
                            $("#%(id)s").width(width + 'px');
                        $('#%(id)s option:first').attr('selected', 'selected');
                        var auto_choose = %(auto_choose)s;
                        if(init_value){
                            $('#%(id)s option[value="'+ init_value +'"]').attr('selected', 'selected');
                        }
                        if(auto_choose && j.length == 1){
                            $('#%(id)s option[value="'+ j[0].value +'"]').attr('selected', 'selected');
                        }
                        $("#%(id)s").trigger('change');
                    })
                }

                if(!$("#id_%(chainfield)s").hasClass("chained")){
                    var val = $("#id_%(chainfield)s").val();
                    fill_field(val, "%(value)s");
                }

                $("#id_%(chainfield)s").change(function(){
                    var start_value = $("#%(id)s").val();
                    var val = $(this).val();
                    fill_field(val, start_value);
                })
            })

            dismissAddAnotherPopup = function(win, newId, newRepr) {
                oldDismissAddAnotherPopup(win, newId, newRepr);
                if (windowname_to_id(win.name) == "id_%(chainfield)s") {
                    $("#id_%(chainfield)s").change();
                }
            }
            var oldDismissAddAnotherPopup = dismissAddAnotherPopup;
        })(jQuery || django.jQuery);
        //]]>
        </script>

        """ % {"chainfield":chain_field, "url":url, "id":attrs['id'], 'value':value, 'auto_choose':auto_choose, 'empty_label': empty_label}
        final_choices = []

        if value:
            item = self.queryset.filter(pk=value)[0]
            try:
                pk = getattr(item, self.model_field + "_id")
                filter = {self.model_field:pk}
            except AttributeError:
                try: # maybe m2m?
                    pks = getattr(item, self.model_field).all().values_list('pk', flat=True)
                    filter = {self.model_field + "__in":pks}
                except AttributeError:
                    try: # maybe a set?
                        pks = getattr(item, self.model_field + "_set").all().values_list('pk', flat=True)
                        filter = {self.model_field + "__in":pks}
                    except: # give up
                        filter = {}
            filtered = list(get_model(self.app_name, self.model_name).objects.filter(**filter).distinct())
            filtered.sort(cmp=locale.strcoll, key=lambda x:unicode_sorter(unicode(x)))
            for choice in filtered:
                final_choices.append((choice.pk, unicode(choice)))
        if len(final_choices) > 1:
            final_choices = [("", (empty_label))] + final_choices
        if self.show_all:
            final_choices.append(("", (empty_label)))
            self.choices = list(self.choices)
            self.choices.sort(cmp=locale.strcoll, key=lambda x:unicode_sorter(x[1]))
            for ch in self.choices:
                if not ch in final_choices:
                    final_choices.append(ch)
        self.choices = ()
        final_attrs = self.build_attrs(attrs, name=name)
        if 'class' in final_attrs:
            final_attrs['class'] += ' chained'
        else:
            final_attrs['class'] = 'chained'
        output = super(ChainedSelect, self).render(name, value, final_attrs, choices=final_choices)
        output += js
        return mark_safe(output)

D I know how to check if jquery is already loaded in JS. But how to deal with it Django, don't know. Also sometime I think that stuff still works but sometime not. Don't understanding why it is happening. Above is what I have concluded after undefined $('.datepicker').datepicker() and by inspecting from firebug. Also some time this code doesn't cause problem. I don't understand why.

Please tell if you guys have any idea. and please ask if I am not clear enough.

thanks


Updated

Here is how I loaded jquery and jquery ui :

    <!DOCTYPE html>
<html class="no-js" lang="en">
<head>
  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
  <title>Kaasib.com</title>
  <meta name="description" content="">
  <meta name="viewport" content="width=device-width">
  <link rel="stylesheet" href="{{STATIC_URL}}css/style.css" />
  <link rel="stylesheet" href="{{STATIC_URL}}css/ui-lightness/jquery-ui-1.8.23.custom.css" />
  <script src="{{STATIC_URL}}js/libs/jquery-1.7.1.min.js"></script>
  <script src="{{STATIC_URL}}js/libs/jquery-ui-1.8.23.custom.min.js "></script>

  <script src="{{STATIC_URL}}js/main.js"></script>
</head> 
Hafiz
  • 4,187
  • 12
  • 58
  • 111
  • are you loading jquery from any place other than `class Media` on `ChainedSelect` ? – karthikr Sep 14 '12 at 02:58
  • @karthikr it is in my template's head section – Hafiz Sep 14 '12 at 06:50
  • @karthikr I am loading it in template's head section,so isn't it right? is there a better way to load jquery in django? please tell, I am not django expert. – Hafiz Sep 14 '12 at 20:19
  • I would just remove this and try: class Media: if USE_DJANGO_JQUERY: js = [static('admin/%s' % i) for i in ('js/jquery.min.js', 'js/jquery.init.js')] elif JQUERY_URL: js = ( JQUERY_URL, ) – karthikr Sep 14 '12 at 21:20
  • @karthikr after doing above, it didn't load the second jquery but still $('.datepicker').datepicker() is not defined error. – Hafiz Sep 14 '12 at 21:43

1 Answers1

0

Ok got the issue, Problem was at my end,I was having an error, Error: ReferenceError: dismissAddAnotherPopup is not defined Source File: http://localhost:8000/jobs/create Line: 195

So I fixed that by placing this var oldDismissAddAnotherPopup = dismissAddAnotherPopup; line after dismissAddAnotherPopup() function definition. Don't know why but it started creating problem so I again have that js error but now my code is working and it is showing datepicker.

Also there was some code in my template file that was again loading jquery. So sorry guys that was my own fault as I was using HTML5 boilerplate in bit wrong way. So only good info for yu from this question is to first check the usage of something properly and then use that.

Hafiz
  • 4,187
  • 12
  • 58
  • 111