geex-arts / django-jet

Modern responsive template for the Django admin interface with improved functionality. We are proud to announce completely new Jet. Please check out Live Demo
https://github.com/jet-admin/jet-bridge
GNU Affero General Public License v3.0
3.57k stars 776 forks source link

Jquery on Change not working on ChoiceField #161

Open yalit opened 7 years ago

yalit commented 7 years ago

Hi there,

I'm trying to attach specific display on the values of a select drop-down (multiple choice field) but it's not working. I see that it's not the select itself that is displayed but an added with the following id : select2-id_ptype-container. Using jquery .change() on the select, nothing happens (as if due to the overwrite of the display, the change on the select isn't fired)

How should I approach this?

ptype = models.IntegerField(choices=TYPE_CHOICES, verbose_name="Type de la personne")

Select généré

<select id="id_ptype" name="ptype" required>

span ajouté

<span class="select2 select2-container select2-container--jet select2-container--below" dir="ltr" style="width: auto;">
<span class="selection">
    <span class="select2-selection select2-selection--single" role="combobox" aria-autocomplete="list" aria-haspopup="true" aria-expanded="false" tabindex="0" aria-labelledby="select2-id_ptype-container">
        <span class="select2-selection__rendered" id="select2-id_ptype-container" title="Type1">Type1</span><span class="select2-selection__arrow" role="presentation"><b role="presentation"></b>
        </span>
    </span>
</span>

FRReinert commented 7 years ago

I'm having the same problem.

I think it happens because the <select> used by the user is dinamically created, so jQuery can't access it directly.

In theory you could bind the element with ".on()" on the container that the element was dinamically added (this container needs to be on the page when you load it), but it also don't worked for me too... Anyway, the code is something like: $("#FixedContainer").on("click", "#DinamicElement", function(){ // bla bla bla... });

ilubnon commented 7 years ago

In theory it should work. But? The change event does not fire. And calling the select2 plugin does not work.

$el.select2(); 
//select2 is not a function. (In 'el.select2()', 'el.select2' is undefined)

I got very close using DOMSubtreeModified, like this:

  $el.on('DOMSubtreeModified', function () {
    alert ( $(this).text() );
  });

But there are many events (bubbles) ...

I do not really know how to get this value when the select changes, if you can, please let me know.

Thank you!

SalahAdDin commented 7 years ago

@f1nality Here there is other problem with jquery.

udanieli commented 7 years ago

I've got the same issue here, the change event does not fire. Are we listening on the wrong object?

Ismael-VC commented 7 years ago

I have the same problem when trying to embebed a Google Maps map inside a dashboard module that displays routes, the route displayed changes according to the place selected, but in django-jet the event is never fired, opening the template in a stand alone tab in chrome, works fine. There are also selection issues in FireFox. I see there are a lot of issues with Select-2 @f1nality is there an alternative to this library?

Ismael-VC commented 7 years ago

In latest dev, if I click the select option it doesn't even pick it up, the options pop up just stays there:

image

SalahAdDin commented 7 years ago

@Ismael-VC can you provide a traceback from debug console in browser or from console in python? Thanks!

Ismael-VC commented 7 years ago

@SalahAdDin sure thing, this is the working map, just opening the template in a new tab:

image

Here is the Maps dashboard module template:

{% load humanize %}

<div style="text-align: center;">
    <b>Start: </b>
    <select id="route_start">
        <option value="Ciudad de Queretaro">Queretaro</option>
        <option value="Ciudad de Hermosillo">Hermosillo</option>
    </select>
    <b>End: </b>
    <select id="route_end">
        <option value="Ciudad de México">México</option>
        <option value="Ciudad de Sonora">Sonora</option>
    </select>
</div>

<div id="route_map" style="width: 100%; height: 350px;"></div>

<script>
    function initMap() {
        // ROUTE MAP
        var routeMapCanvas = document.getElementById("route_map");
        var routeMapOptions = {
            center: new google.maps.LatLng(19.3910036, -99.2840421),
            zoom: 7,
            panControl: true,
            zoomControl: true,
            mapTypeControl: true,
            scaleControl: true,
            streetViewControl: true,
            overviewMapControl: true,
            rotateControl: true
        };
        var route_map = new google.maps.Map(routeMapCanvas, routeMapOptions);

        var directionsService = new google.maps.DirectionsService;
        var directionsDisplay = new google.maps.DirectionsRenderer;
        directionsDisplay.setMap(route_map);

        function onChangeHandler() {
            calculateAndDisplayRoute(directionsService, directionsDisplay);
        };

        // Event listeners to select elements:
        document.getElementById("route_start").addEventListener('click', onChangeHandler);
        document.getElementById('route_end').addEventListener('change', onChangeHandler)
    }

    function calculateAndDisplayRoute(directionsService, directionsDisplay) {
        directionsService.route({
            origin: document.getElementById('route_start').value,
            destination: document.getElementById('route_end').value,
            travelMode: google.maps.TravelMode.DRIVING
        }, function (response, status) {
            if (status === google.maps.DirectionsStatus.OK) {
                directionsDisplay.setDirections(response);
            } else {
                window.alert('Directions request failed due to ' + status);
            }
        });
    }

</script>

<script src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&callback=initMap"></script>

Here is the error when I try to select an option:

image

This is the traceback:

2017-04-09 11:56:53.030 bundle.min.js?v=1.0.5:1 Uncaught TypeError: django.jQuery is not a function
    at HTMLSelectElement.<anonymous> (bundle.min.js?v=1.0.5:1)
    at HTMLSelectElement.dispatch (bundle.min.js?v=1.0.5:9)
    at HTMLSelectElement.m.handle (bundle.min.js?v=1.0.5:9)
    at Object.trigger (bundle.min.js?v=1.0.5:9)
    at HTMLSelectElement.<anonymous> (bundle.min.js?v=1.0.5:9)
    at Function.each (bundle.min.js?v=1.0.5:8)
    at ot.fn.init.each (bundle.min.js?v=1.0.5:7)
    at ot.fn.init.trigger (bundle.min.js?v=1.0.5:9)
    at n.select (bundle.min.js?v=1.0.5:12)
    at o.<anonymous> (bundle.min.js?v=1.0.5:12)
(anonymous) @ bundle.min.js?v=1.0.5:1
dispatch @ bundle.min.js?v=1.0.5:9
m.handle @ bundle.min.js?v=1.0.5:9
trigger @ bundle.min.js?v=1.0.5:9
(anonymous) @ bundle.min.js?v=1.0.5:9
each @ bundle.min.js?v=1.0.5:8
each @ bundle.min.js?v=1.0.5:7
trigger @ bundle.min.js?v=1.0.5:9
n.select @ bundle.min.js?v=1.0.5:12
(anonymous) @ bundle.min.js?v=1.0.5:12
n.invoke @ bundle.min.js?v=1.0.5:11
n.trigger @ bundle.min.js?v=1.0.5:11
o.trigger @ bundle.min.js?v=1.0.5:13
(anonymous) @ bundle.min.js?v=1.0.5:13
n.invoke @ bundle.min.js?v=1.0.5:11
n.trigger @ bundle.min.js?v=1.0.5:11
(anonymous) @ bundle.min.js?v=1.0.5:11
dispatch @ bundle.min.js?v=1.0.5:9
m.handle @ bundle.min.js?v=1.0.5:9

At first I thought it was related to django-autocomplete-light:

INSTALLED_APPS = [
    # django-autocomplete-light
    # 'dal',
    # 'dal_select2',

    # Jet Bootstrap
    'jet.dashboard',
    'jet',
    # ...
]

But this is the error shown: TypeError: django.jQuery is not a function and this still happens when I disable dal and dal_select2.

Ismael-VC commented 7 years ago

@f1nality here is the code from bundle.min.js at the initSelect function:

initSelect: function(t, e) {
    var i = {
        theme: "jet",
        dropdownAdapter: e,
        width: "auto"
    };
    if (t.hasClass("ajax")) {
        var n = t.data("content-type-id")
          , o = t.data("app-label")
          , s = t.data("model")
          , r = t.data("object-id")
          , a = 100;
        i.ajax = {
            dataType: "json",
            data: function(t) {
                return {
                    content_type: n,
                    app_label: o,
                    model: s,
                    q: t.term,
                    page: t.page,
                    page_size: a,
                    object_id: r
                }
            },
            processResults: function(t, e) {
                if (t.error)
                    return {};
                e.page = e.page || 1;
                var i = e.page * a < t.total;
                return {
                    results: t.items,
                    pagination: {
                        more: i
                    }
                }
            }
        }
    }
    t.on("change", function(e) {
        django.jQuery(t.get(0)).trigger(e)    // Here the exception is thrown.
    }),
    t.select2(i)
},

So this means Select2 is never initialized.

Ismael-VC commented 7 years ago

The file in question is: static\jet\build\bundle.min.js

I have tried manually editing this generated file like this:

t.on("change", function(e) {
    var $ = jQuery.noConflict(true); 
    $(t.get(0)).trigger(e)
})

But I'm still learning JS and I think this file is cached somewhere, because I don't see the cange being reflected, I'll keep trying to make it work.

SalahAdDin commented 7 years ago

@Ismael-VC Is these bundle yours or comes from django-jet project?

Ismael-VC commented 7 years ago

@SalahAdDin It's part of django-jet dev.

Ismael-VC commented 7 years ago

@SalahAdDin @f1nality I have figured out that part of the file static\jet\build\bundle.min.js is built from jet/static/jet/js/src/features/selects.js

Combined JS scripts of JET – jet/static/jet/js/build/bundle.min.js

I should have red CONTRIBUTING sooner, this is the commit that introduced the line with django.jQuery, it's there to fix some previous problem (maybe intended to close this issue?):

Ismael-VC commented 7 years ago

The problem with Uncaught TypeError: django.jQuery is not a function only happens in the /admin page, other views are not affected AFAICT:

image

SalahAdDin commented 7 years ago

Maybe the problem is a merge ordering of the scripts.

Ismael-VC commented 7 years ago

@SalahAdDin could you please update and try to reproduce this error please? @f1nality has just merged dev back into master a few hours ago:

SalahAdDin commented 7 years ago

Ok, i'll install it from master.

Ismael-VC commented 7 years ago

django.jQuery is used only at:

According to git grep "django.jQuery", but I can't see where it is defined anywhere. django.jQuery is undefined in /admin:

image

However it is defined in the other pages, here /admin/catalogs_app/unit/, where catalogs_app is my main app, but it also works in other apps:

image

If I double click the output of django.jQuery in the chrome console, it opens the file in the line where jQuery is defined, in jquery.js itself.

Ismael-VC commented 7 years ago

Ok, I'm beginning to get the hang out of this, I have done the following:

  1. Fork django-jet
  2. Install node and gulp
  3. Run node install in the django-jet dir, to install all dependencies
  4. Run gulp to listen for any changes in the static files and to rebuild automatically: static\jet\build\bundle.min.js
  5. I've edited `jet/static/jet/js/src/features/selects.js``
diff --git a/jet/static/jet/js/src/features/selects.js b/jet/static/jet/js/src/features/selects.js
index 7f99f6f..47d5227 100644
--- a/jet/static/jet/js/src/features/selects.js
+++ b/jet/static/jet/js/src/features/selects.js
@@ -190,7 +190,7 @@ Select2.prototype = {
         }

         $select.on('change', function(e) {
-            django.jQuery($select.get(0)).trigger(e);
+            $($select.get(0)).trigger(e);
         });

         $select.select2(settings);

But this causes: Uncaught RangeError: Maximum call stack size exceeded

image

I don't really understand why.

Ismael-VC commented 7 years ago

This is the whole backtrace for that error:

Ismael-VC commented 7 years ago

Ok I've also tried changing to:

diff --git a/jet/static/jet/js/src/features/selects.js b/jet/static/jet/js/src/features/selects.js 
index 7f99f6f..5c8095a 100644                                                                      
--- a/jet/static/jet/js/src/features/selects.js                                                    
+++ b/jet/static/jet/js/src/features/selects.js                                                    
@@ -190,6 +190,8 @@ Select2.prototype = {                                                          
         }                                                                                         

         $select.on('change', function(e) {                                                        
+            var django = django || {};                                                            
+            django.jQuery = jQuery.noConflict(true);                                              
             django.jQuery($select.get(0)).trigger(e);                                             
         });                                                                                       

But now the Chrome console, tells me that Uncaught TypeError: Cannot read property 'noConflict' of undefined, so django is also undefined in /admin. :(

I found django.jQuery is defined at:

Here is a comment and issue that seems relevant:

Sorry, I make a mistake. I found the real jquery.init.js file comes from django-autocomplete-light package. this project rewrite jquery.init.js file.

I did had django-autocomplete-light installed at some point, but I uninstalled it, deleted static in my project and re ran collectstatic, however, since I clearly don't know JS-fu, I'll start from scratch and see if it happens.

@SalahAdDin were you able to reproduce this error? If you can't then that means it's only on my side, and that would make me think it really had something to do with django-autocomplete-light.

Ismael-VC commented 7 years ago

@f1nality I can reproduce this in a completely new environment, a new project and using current django-jet master.

Steps to reproduce:

STATICFILES_FINDERS = [ 'django.contrib.staticfiles.finders.FileSystemFinder', 'django.contrib.staticfiles.finders.AppDirectoriesFinder', ]

* Configure urls:
```python
from django.conf.urls import url, include
from django.contrib import admin

urlpatterns = [
    url(r'^jet/', include('jet.urls', 'jet')),
    url(r'^jet/dashboard/', include('jet.dashboard.urls', 'jet-dashboard')),
    url(r'^admin/', admin.site.urls),
]
Ismael-VC commented 7 years ago

image

Ismael-VC commented 7 years ago

@SalahAdDin @f1nality where you able to reproduce this?

jelitox commented 7 years ago

Hi, I'm having this issue, all selects in django-admin return on Uncaught TypeError: django.jQuery is not a function, there is some workaround that can be apply?

arbak commented 7 years ago

Add to folder : jet/static/jet/js/build/ file jquery.init.js with a code:

/*global django:true, jQuery:false*/
/* 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 = django || {};
django.jQuery = jQuery.noConflict(true);

next in file: jet/templates/admin/base.html add 2 lines in the head:

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js" type="text/javascript"></script>
<script src="{% static "jet/js/build/jquery.init.js" as url %}{{ url|jet_append_version }}"></script>

It should solve your problem. Success!

SalahAdDin commented 7 years ago

@f1nality what's about @arbak solution?

arbak commented 7 years ago

It will fix : Jquery on Change not working on ChoiceField and django.jQuery is not a function error

thyagotosin commented 7 years ago

@arbak and what about "RangeError: Maximum call stack size exceeded." in all selects in Django-admin? I'm still getting this with Django-jet at master. Any solution?

SalahAdDin commented 7 years ago

@f1nality Please.

thyagotosin commented 7 years ago

nothing yet about a solution?

zodman commented 7 years ago

ref #230 why trigger on recursive ?

https://github.com/geex-arts/django-jet/blob/dev/jet/static/jet/js/src/features/selects.js#L193

SalahAdDin commented 7 years ago

:+1:

rbp commented 7 years ago

Bump? This will end up making me have to remove jet :/

Ismael-VC commented 7 years ago

@rbp Im pissed off too, we need a working django-jet repo, where we can contribute as community and not depend on @f1nality, whom for whichever reason just doesn't care anymore or is unable to continue guiding it's development.

I have already fixed my code locally and made a working PR months ago, see: https://github.com/geex-arts/django-jet/pull/229

@SalahAdDin has contributed to a django-jetpack repo. I think we should update that repo and accept PRs there or elsewhere.

What do you think @SalahAdDin? Obiously to keep pingin @f1nality is not taking us anywhere. If we cant reorganize as community, I'll also have to remove jet in the future.

What do you think guys? Something needs to be done ASAP. :( But if @f1nality can't keep the boat afloat, maybe we should keep it afloat ourselves. Abandoning ship is not the only option.

I'm certaing that if we forked this repo and had someone like @SalahAdDin guide it we could succeed, the problems that need solving are:

Ismael-VC commented 7 years ago

@dbortolz, @yalit, @FRReinert, @ilubnon, @SalahAdDin, @f1nality, @jelitox, @arbak, @thyagotosin, @zodman, @rbp

I'm pinging you because you where interested in this issue.

Please come to my Discord server so we can organize if you like:

I'd like to try organizing a community around this project, before just forgeting about it at all.

Django-jet is cool, it just needs management, it already has a community of users, now we only need to organize!

Ismael-VC commented 7 years ago

If we can figure a way to keep things going forward, then I can start inviting everyone that has contributed or reacted to django-jet to the new project, watch for issues and PRs here, and tell people to please send those our way, etc. We can do this, I mean it.

I sincerely hope @f1nality is well and healthy, but I can't be in this situation anymore, something has to be done, cheers guys! 😄

udanieli commented 7 years ago

In my Python/Django experience I've always known that customizing the admin interface is not an easy task, pushing the admin to the limits is risky. Generally speaking, I would not build an entire web app on the shoulders of the admin interface. If I have special needs I write down some plain Django CBV, it's a matter of minutes. django-jet it is really cool but thanks to a lot of custom JS and CSS, stuff I am not a fan of. You can enjoy its vanilla flavour-features without relying too much on it, if it's going to be a discontinued project. I hope it's not. Good luck to everybody.

SalahAdDin commented 7 years ago

@Ismael-VC, are you leaving the discord group?

rbp commented 7 years ago

Let me put my previous comment in perspective: it wasn't a threat, and I'm not sure a fork is necessarily the best solution.

This is FOSS, kindly written by @f1nality , and it's very useful - so much so that we're all here clamouring for more. I didn't mean to imply that he was doing a bad job, nor that he had any obligation to address our needs, and I'm sorry if I came across that way.

That said, there's clearly the need for faster development. A fork is always a possibility, but it's a somehow drastic one. Besides, who's to say that the fork will then keep on being developed? I'm sure @f1nality didn't plan on a hiatus, when he started this. Nobody is exempt from starting/picking up a project with the best intentions and then having to step away for a while, or drop it completely.

So, my suggestion to the people willing to take matters into their own hands is: reach out to @f1nality , and see if you can join as co-admins of the project. This immediately means more hands and eyes on the project, more PR reviewers, and hopefully a faster pace. It also means less fragmentation, and the continuation of what's after all a very nice project.

I'm in now way volunteering to do any of this - I have far too little time in my hands, and I've already forked django-jet to apply this fix. But I've seen way too many well-intentioned forks that end up as dead as the original project, and I hope we can avoid this here.

Best of luck!

SalahAdDin commented 7 years ago

@rbp You are right, my idea now, for now, is have a branch in our fork with this fixings and install this package from theme for awhile. @Ismael-VC What do you think about it?¡

FRReinert commented 7 years ago

I already remove jet from my projects.

Enviado do meu iPhone

Em 14 de ago de 2017, às 15:10, Ismael Venegas Castelló notifications@github.com<mailto:notifications@github.com> escreveu:

@dbortolzhttps://github.com/dbortolz, @yalithttps://github.com/yalit, @FRReinerthttps://github.com/frreinert, @ilubnonhttps://github.com/ilubnon, @SalahAdDinhttps://github.com/salahaddin, @f1nalityhttps://github.com/f1nality, @jelitoxhttps://github.com/jelitox, @arbakhttps://github.com/arbak, @thyagotosinhttps://github.com/thyagotosin, @zodmanhttps://github.com/zodman, @rbphttps://github.com/rbp

I'm pinging you because you where interested in this issue.

Please come to my Discord server so we can organize if you like:

I'd like to try organizing a community around this project, before just forgeting about it at all.

Django-jet is cool, it just needs management, it already has a community of users, now we only need to organize!

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHubhttps://github.com/geex-arts/django-jet/issues/161#issuecomment-322265301, or mute the threadhttps://github.com/notifications/unsubscribe-auth/AYVNi0jP_a9Kt7dILS3aRcMHpvwUQlNcks5sYI2dgaJpZM4LXkG9.

SalahAdDin commented 7 years ago

@FRReinert Which alternative are you using now?

Ismael-VC commented 7 years ago

@SalahAdDin the discord server is there to stay! ;)

@rbp don't worry no one said your was a threat!

reach out to @f1nality

This has been done uncountable times, via email, github, you name it! I'm not saying django-jet is bad or that he did a bad job, but he does has abandoned the project, the django-jetpack fork is evidence of that.

In the begining I also told @SalahAdDin to try not to fork, to try to talk with @f1nality, just as you said, but that was months ago.

@SalahAdDin either has great patience or great expectations for @f1nality. I just want to move on.

I get what you say about the other fork could also die, and that's true, but django-jet is already dead, @f1nality is not going to give access to anyone else, nor answer or calls. There are other people who have also write access, judging by the commit log, but guess what, no answer or no way to contact them either.

I'm doing this not because, I hate anyone or am mad, I just really need to move forward, be it here or with an alternative, but I have already learned so much by reading django-jet source, taht I would like to document it even more, but not even that is accepted.

Jet is dead RIP, well *this** repo is dead, the last time there was a merge to master was when this bug was introduced, no fix, no merge my PR, just anything.

If you guys want to keep waiting for him I understand, if you guys want to abandon ship I understand, but I'm going to try keeping a for up to date and accept PR's there before I thorw the towell.

Cheers!

thyagotosin commented 7 years ago

Let's do it. Jet can't stop.

Ismael-VC commented 7 years ago

@SalahAdDin I can make you admin of the Discord server, just ask me! 😄

SalahAdDin commented 7 years ago

It still is happening inclusive after https://github.com/geex-arts/django-jet/commit/45e94712b35409652bf984bcadcdbc923c2ec2ae#diff-00db1b427cdf9ae5b3b45e603ae3225a

SalahAdDin commented 7 years ago

@arbak Do your solution create other buds?

Olerdrive commented 6 years ago

That bug still occurs in the latest dev

SalahAdDin commented 6 years ago

Some one have a fix for it?