yourlabs / django-autocomplete-light

A fresh approach to autocomplete implementations, specially for Django. Status: v4 alpha, v3 stable, v2 & v1 deprecated.
https://django-autocomplete-light.readthedocs.io
MIT License
1.8k stars 467 forks source link

The jQuery inits are not loaded in the correct order in 3.5.1 #1137

Open MartinFalatic opened 4 years ago

MartinFalatic commented 4 years ago

There's a lot going on below, but the heart of the problem is that in 3.5.0, /static/admin/js/jquery.init.js is loaded before /static/autocomplete_light/jquery.init.js (which works) and in 3.5.1 it's the opposite (which fails). Making that one change alone (building with 3.5.0 as the basis) is enough to trigger this failure.

Given Django 3.0.3 with:

INSTALLED_APPS = [
    'corsheaders',
    'dal',
    'dal_select2',
    'django.contrib.admin',
    'django.contrib.auth',
    .....

In 3.5.0, django-autocomplete-light works fine, but in 3.5.1 it doesn't.

The main console error is Select2: An instance of jQuery or a jQuery-compatible library was not found. Make sure that you are including jQuery before Select2 on your web page. followed by jQuery.Deferred exception: $(...).select2 is not a function TypeError: $(...).select2 is not a function

However, we do load it - but the load order is slightly different between 3.5.0 and 3.5.1. Here's the header of the admin page in question:

Built with 3.5.0:

<!DOCTYPE html>

<html lang="en-us" >
<head>
<title>Add Organization settings | Django site admin</title>
<link rel="stylesheet" type="text/css" href="/static/admin/css/base.css">
<link rel="stylesheet" type="text/css" href="/static/admin/css/forms.css">

<script type="text/javascript" src="/admin/jsi18n/"></script>
<link href="/static/vendor/select2/dist/css/select2.css" type="text/css" media="screen" rel="stylesheet">
<link href="/static/admin/css/autocomplete.css" type="text/css" media="screen" rel="stylesheet">
<link href="/static/autocomplete_light/select2.css" type="text/css" media="screen" rel="stylesheet">
<script type="text/javascript" src="/static/admin/js/vendor/jquery/jquery.js"></script>
<script type="text/javascript" src="/static/admin/js/jquery.init.js"></script>
<script type="text/javascript" src="/static/autocomplete_light/jquery.init.js"></script>
<script type="text/javascript" src="/static/admin/js/core.js"></script>
<script type="text/javascript" src="/static/vendor/select2/dist/js/select2.full.js"></script>
<script type="text/javascript" src="/static/admin/js/admin/RelatedObjectLookups.js"></script>
<script type="text/javascript" src="/static/vendor/select2/dist/js/i18n/en.js"></script>
<script type="text/javascript" src="/static/admin/js/actions.js"></script>
<script type="text/javascript" src="/static/autocomplete_light/autocomplete.init.js"></script>
<script type="text/javascript" src="/static/admin/js/urlify.js"></script>
<script type="text/javascript" src="/static/autocomplete_light/forward.js"></script>
<script type="text/javascript" src="/static/admin/js/prepopulate.js"></script>
<script type="text/javascript" src="/static/autocomplete_light/select2.js"></script>
<script type="text/javascript" src="/static/admin/js/vendor/xregexp/xregexp.js"></script>
<script type="text/javascript" src="/static/autocomplete_light/jquery.post-setup.js"></script>

.....

Built with 3.5.1:

<!DOCTYPE html>

<html lang="en-us" >
<head>
<title>Add Organization settings | Django site admin</title>
<link rel="stylesheet" type="text/css" href="/static/admin/css/base.css">
<link rel="stylesheet" type="text/css" href="/static/admin/css/forms.css">

<script type="text/javascript" src="/static/admin/js/vendor/jquery/jquery.js"></script>
<script type="text/javascript" src="/admin/jsi18n/"></script>
<link href="/static/vendor/select2/dist/css/select2.css" type="text/css" media="screen" rel="stylesheet">
<link href="/static/admin/css/autocomplete.css" type="text/css" media="screen" rel="stylesheet">
<link href="/static/autocomplete_light/select2.css" type="text/css" media="screen" rel="stylesheet">
<script type="text/javascript" src="/static/autocomplete_light/jquery.init.js"></script>
<script type="text/javascript" src="/static/admin/js/jquery.init.js"></script>
<script type="text/javascript" src="/static/vendor/select2/dist/js/select2.full.js"></script>
<script type="text/javascript" src="/static/admin/js/core.js"></script>
<script type="text/javascript" src="/static/vendor/select2/dist/js/i18n/en.js"></script>
<script type="text/javascript" src="/static/admin/js/admin/RelatedObjectLookups.js"></script>
<script type="text/javascript" src="/static/autocomplete_light/autocomplete.init.js"></script>
<script type="text/javascript" src="/static/admin/js/actions.js"></script>
<script type="text/javascript" src="/static/autocomplete_light/forward.js"></script>
<script type="text/javascript" src="/static/admin/js/urlify.js"></script>
<script type="text/javascript" src="/static/autocomplete_light/select2.js"></script>
<script type="text/javascript" src="/static/admin/js/prepopulate.js"></script>
<script type="text/javascript" src="/static/autocomplete_light/jquery.post-setup.js"></script>
<script type="text/javascript" src="/static/admin/js/vendor/xregexp/xregexp.js"></script>

.....

Things work fine with 3.5.0. If you use 3.5.1 things break, and if you then substitute the 3.5.0 header (via Chrome dev tools overrides) it'll work again.

jpic commented 4 years ago

Thanks for the report, does it work if you remove jquery.init.js from dal ?

MartinFalatic commented 4 years ago

How should one go about doing that?

raratiru commented 4 years ago

Could be relevant to #1143

jpic commented 4 years ago

Does it work with #1147 ?

jpic commented 4 years ago

Also published in : django-autocomplete-light==3.6.0-dev

Please try it out, it is expected to break fix in theory, but to fix things in practice, regarding jquery et al.

schyffel commented 4 years ago

This broke dal-select2 for me as well, because it changed js loading order. Pinning to version 3.5.0 works for me.

MartinFalatic commented 4 years ago

Has there been any progress on this issue?

jpic commented 4 years ago

Feedback still awaited for #1147, no other PR in sight

MartinFalatic commented 4 years ago

Giving this a try today - trying to reproduce the original issue with 3.5.1 first.

MartinFalatic commented 4 years ago

@jpic I appreciate your patience - I was on another project for a while, and when I came back to this I didn't realize there was a dev version.

I just tested with django-autocomplete-light==3.6.0.dev1 and so far I'm not seeing any problems in my dev environment, which is good.

I've also been trying to reproduce the original problem in a local environment with 3.5.1 and haven't succeeded - I wonder if other updates had some positive effect as well, or if 3.5.1 actually just works sometimes and not others. Either way, I'm grateful that progress was made on this.

jpic commented 4 years ago

@MartinFalatic Thank you for the kind words, to be completely honest I don't remember making 3.6.0.dev1, I do remember that for literally years when I change this, it fixes problems for some users and create problems for others, and personally I've moved on to webpack years ago already because this lets me have the same kind work flow for frontend code as with backend code (modules, imports).

As such, please keep in mind that I'm mostly blindly hacking on this, I'm going to need autocompletion in a Django project of mine this year (a KISS sentry+gitlab+ci alternative), but it's built on CRUDLFA+ and Ryzom, so not sure how many tools of DAL I'll be using, but definitely will be reviving the older jquery-autocomplete-light so we'll have a select2 alternative again that would not only open doors to new possibilities with your autocomplete, but also make sure that there is no conflict by leaving select2 completely to Django, if you so wish.

Please, can you double check that 3.6.0.dev1 is ready to release, it's great that you could confirm that it fixed your problem, I'm very thankful for that in the name of the community, but can I ask you to try to understand what's going on and let me know if you think that the proposed fix also is sound in theory, and if there's any theorical drawbacks what they would be.

Thanks you very much

MartinFalatic commented 4 years ago

I'm going to try more with this this coming week (I want to replicate the original problem before I call this done, and it was a very busy week). I'm pretty sure it's working, but I want to make sure I'm actually exercising the right part of the system.

I'm curious what the situation is in this comment:

https://github.com/yourlabs/django-autocomplete-light/issues/1143#issuecomment-601919205

It'd be good to know if this solves the problem for them too.

MartinFalatic commented 4 years ago

@jpic So I logged into work and found the discussion we had about this back in Feb, and using that I was able to replicate the same conditions.

3.6.0dev1 seems to work - the only oddity versus 3.5.0 in the inspection window is that there is a failed attempt to load <site>/static/autocomplete_light/jquery.init.js, followed by a successful attempt to load <site>/static/admin/js/jquery.init.js.

Here's the page header with 3.5.0. (This virtually identical to how 3.5.0 looked when I originally reported this, with the recent addition of "inlines" and the fact that some of these items are minified now):

/static/autocomplete_light/jquery.init.js is present

<!DOCTYPE html>

<html lang="en-us" >
<head>
<title>Add Organization settings | Django site admin</title>
<link rel="stylesheet" type="text/css" href="/static/admin/css/base.css">
<link rel="stylesheet" type="text/css" href="/static/admin/css/forms.css">

<script type="text/javascript" src="/admin/jsi18n/"></script>
<link href="/static/vendor/select2/dist/css/select2.min.css" type="text/css" media="screen" rel="stylesheet">
<link href="/static/admin/css/autocomplete.css" type="text/css" media="screen" rel="stylesheet">
<link href="/static/autocomplete_light/select2.css" type="text/css" media="screen" rel="stylesheet">
<script type="text/javascript" src="/static/admin/js/vendor/jquery/jquery.min.js"></script>
<script type="text/javascript" src="/static/admin/js/jquery.init.js"></script>
<script type="text/javascript" src="/static/autocomplete_light/jquery.init.js"></script>
<script type="text/javascript" src="/static/admin/js/core.js"></script>
<script type="text/javascript" src="/static/vendor/select2/dist/js/select2.full.min.js"></script>
<script type="text/javascript" src="/static/admin/js/inlines.min.js"></script>
<script type="text/javascript" src="/static/admin/js/admin/RelatedObjectLookups.js"></script>
<script type="text/javascript" src="/static/vendor/select2/dist/js/i18n/en.js"></script>
<script type="text/javascript" src="/static/admin/js/actions.min.js"></script>
<script type="text/javascript" src="/static/autocomplete_light/autocomplete.init.js"></script>
<script type="text/javascript" src="/static/admin/js/urlify.js"></script>
<script type="text/javascript" src="/static/autocomplete_light/forward.js"></script>
<script type="text/javascript" src="/static/admin/js/prepopulate.min.js"></script>
<script type="text/javascript" src="/static/autocomplete_light/select2.js"></script>
<script type="text/javascript" src="/static/admin/js/vendor/xregexp/xregexp.min.js"></script>
<script type="text/javascript" src="/static/autocomplete_light/jquery.post-setup.js"></script>

.....

Here's the page header with 3.6.1dev1 in use:

/static/autocomplete_light/jquery.init.js is ABSENT

<!DOCTYPE html>

<html lang="en-us" >
<head>
<title>Add Organization settings | Django site admin</title>
<link rel="stylesheet" type="text/css" href="/static/admin/css/base.css">
<link rel="stylesheet" type="text/css" href="/static/admin/css/forms.css">

<script type="text/javascript" src="/admin/jsi18n/"></script>
<link href="/static/vendor/select2/dist/css/select2.min.css" type="text/css" media="screen" rel="stylesheet">
<link href="/static/admin/css/autocomplete.css" type="text/css" media="screen" rel="stylesheet">
<link href="/static/autocomplete_light/select2.css" type="text/css" media="screen" rel="stylesheet">
<script type="text/javascript" src="/static/admin/js/vendor/jquery/jquery.min.js"></script>
<script type="text/javascript" src="/static/autocomplete_light/jquery.init.js"></script>
<script type="text/javascript" src="/static/admin/js/jquery.init.js"></script>
<script type="text/javascript" src="/static/vendor/select2/dist/js/select2.full.min.js"></script>
<script type="text/javascript" src="/static/admin/js/core.js"></script>
<script type="text/javascript" src="/static/vendor/select2/dist/js/i18n/en.js"></script>
<script type="text/javascript" src="/static/admin/js/inlines.min.js"></script>
<script type="text/javascript" src="/static/admin/js/admin/RelatedObjectLookups.js"></script>
<script type="text/javascript" src="/static/autocomplete_light/autocomplete.init.js"></script>
<script type="text/javascript" src="/static/admin/js/actions.min.js"></script>
<script type="text/javascript" src="/static/autocomplete_light/forward.js"></script>
<script type="text/javascript" src="/static/admin/js/urlify.js"></script>
<script type="text/javascript" src="/static/autocomplete_light/select2.js"></script>
<script type="text/javascript" src="/static/admin/js/prepopulate.min.js"></script>
<script type="text/javascript" src="/static/admin/js/vendor/xregexp/xregexp.min.js"></script>

.....
raratiru commented 4 years ago

It'd be good to know if this solves the problem for them too.

In my case (#1143 ), the problem appears in 3.5.1 and continues unsolved, when an inline with a DAL field coexists with an inline with a django admin autocomplete field, even when I provide explicitly the JQuery file in the Media metaclass of the relevant form:

# This does not work in 3.5.1 or in 3.6.0-dev1
class Admin(admin.ModelAdmin):
    inlines = ('WithAutocompleteInline', 'WithDALIline')
micjabbour commented 4 years ago

Thank you all for the great work :+1:

:warning: Disclaimer: :warning: Please excuse any mistakes I might have done below. I am quite new to Django and JavaScript, but I am trying to put my two cents in anyway. :smile:

In my opinion, the initial issue report seems to highlight the crux of the problem: the absence of any constraints that determine the order of 'admin/js/jquery.init.js' and 'autocomplete_light/jquery.init.js'. As far as I understand, this means that we are relying on internal details in Django's stable topological sort algorithm, which seems to have been producing undesirable ordering since the removal of 'admin/js/vendor/jquery/jquery.js' in release 3.5.1 (which, ideally, shouldn't have any effect on the ordering of the aforementioned jquery init files).

I also took a look at the new approach the library seems to be heading into currently in the master branch (that is, the removal of 'autocomplete_light/jquery.init.js', and making the other scripts more lenient on how they access jQuery). However, in my opinion, this shifts the ordering problem to 'admin/js/vendor/select2/select2.full.js' and 'admin/js/jquery.init.js'. With no constrains in place, Django is free to place any of them before the other and dal still requires that the former be loaded before the latter in order to work. Despite that the approach seems to be working at the moment, a seemingly unrelated change might cause Django to change the order later and suddenly break things (similar to what happened in release 3.5.1).

Personally, I worked around this issue in 3.5.1, by adding a Media class to my admin forms/classes that adds the missing constraint:

    class Media:
        js = [
            'admin/js/jquery.init.js',
            'autocomplete_light/jquery.init.js',
        ]

I understand that this is impossible to include in the library, because it breaks Select2WidgetMixin when used outside django-admin. Therefore, I am proposing that the library includes a mixin that adds a similar Media class, and documents that the user is responsible for inheriting this mixin in their admin forms/classes in order to insert the missing constraint (i.e. similar to how the documentation currently instructs the user to make sure jQuery is properly included when using the library outside of the admin).

Thank you very much, any feedback is appreciated...

w- commented 4 years ago

@micjabbour Thank you very much for your detailed writeup. Your soln solved the issue for me as well.

Not sure, but this issue may be related to https://github.com/yourlabs/django-autocomplete-light/issues/602

jpic commented 4 years ago

This should be fixed in the current master thanks to @danielmorell in #1162 , but you need to read the setup instructions again to build an isolated bundle.

Otherwise, a new frontend is on the way in https://github.com/yourlabs/autocomplete-light with https://github.com/yourlabs/djwc automatic loading of stantard webcomponents.

Please, send feedback about current master so that we figure if we can release or just let DAL 4.0 #1168 obsolete it.

jpic commented 4 years ago

Can anybody confirm this is fixed in 3.7.0.dev0 ?

spapas commented 4 years ago

I have to comment here that I was only able to make it work with django 3.0.8 and dal 3.5.1 using the @micjabbour solution. I had lost more than an hour doing various combinations and tests and only that worked. So many thanks @micjabbour !!!

spapas commented 4 years ago

Hello @jpic sorry for closing the issue I pressed the wrong button!

I tried 3.7.0.dev0 im my project (django 3.0.8) and it seems to be working fine (without using any custom media in my admin form). Thank you for the great work !

udanieli commented 3 years ago

@jpic 3.7.0.dev0 fixes the issue for me, thank you

jpic commented 3 years ago

Awesome, releasing 3.7.0 this week.

Thanks to @danielmorell for the great work :)