Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Select2 not working in inline #134

Open
benmaier opened this issue Nov 1, 2019 · 6 comments
Open

Select2 not working in inline #134

benmaier opened this issue Nov 1, 2019 · 6 comments

Comments

@benmaier
Copy link

benmaier commented Nov 1, 2019

I'm using inline CRUD-Views to add more complex information to objects. My setup is similar to the one described #133. I've noticed that custom select2-widgets are not working properly in modals. It's alright to just use the normal selects in some cases, however, for one particular inline-object, I need something to search through 350,000 entries. Unfortunately, when adding a select2-widget to a custom form, the widget does not work: one cannot enter anything and no request is sent to the "select2/"-urls. I've looked at the source code but I can't seem to find any clue on how to proceed. Help would much appreciated.

paging @luisza because they seem to have developed the Inline-logic.

Here's a repository that has the complete example showing what doesn't work: https://github.com/benmaier/example-django-crud-admin-lte-select2

Here's the definitions of models, forms, and views.

models.py

from django.db import models

class Geoname(models.Model):
    name = models.CharField(max_length=255)
    population = models.PositiveIntegerField(blank=True,null=True)

    def __str__(self):
        return self.name

class Institution(models.Model):
    name = models.CharField(max_length=255)
    city = models.ForeignKey(Geoname,models.SET_NULL,blank=True,null=True)
    responsible_for_places = models.ManyToManyField(Geoname,blank=True,related_name='responsible_institutions')

    def __str__(self):
        return self.name

class CooperationalRelationship(models.Model):
    institution = models.ForeignKey(Institution,models.CASCADE,related_name='cooperational_relationships')
    city = models.ForeignKey(Geoname,models.CASCADE,related_name='institutional_relationships')
    description = models.TextField(blank=True,null=True)

    def __str__(self):
        return "{} <-> {}".format(self.institution, self.city)

forms.py

from django import forms

from .models import (
        Institution,
        Geoname,
        CooperationalRelationship,
    )

from .widgets import (
        SingleGeonameSelectWidget,
        MultipleGeonameSelectWidget,
    )
from django_select2.forms import ModelSelect2MultipleWidget, ModelSelect2Widget

class SingleGeonameSelectWidget(ModelSelect2Widget):
    search_fields = ['name__icontains']

class MultipleGeonameSelectWidget(ModelSelect2MultipleWidget):
    search_fields = ['name__icontains']

class InstitutionForm(forms.ModelForm):
    class Meta:
        model = Institution
        exclude = []
        widgets = {
                    'city': SingleGeonameSelectWidget,
                    'responsible_for_places': MultipleGeonameSelectWidget,
                }

class CooperationalRelationshipForm(forms.ModelForm):
    class Meta:
        model = CooperationalRelationship
        exclude = ['institution']
        widgets = {
                    'city': SingleGeonameSelectWidget,
                  }

views.py

from django.urls import include
from django.conf.urls import url

from cruds_adminlte.crud import CRUDView
from cruds_adminlte.inline_crud import InlineAjaxCRUD

from .models import (
        Institution,
        Geoname,
        CooperationalRelationship,
    )

from .forms import (
        CooperationalRelationshipForm,
        InstitutionForm,
    )

class CooperationalRelationshipInlineCRUDView(InlineAjaxCRUD):
    model = CooperationalRelationship
    base_model = Institution
    inline_field = 'institution'
    title = "Cooperational Relationships"
    list_fields = ['city', 'description', ]
    add_form = CooperationalRelationshipForm
    update_form = CooperationalRelationshipForm

class InstitutionCRUDView(CRUDView):
    model = Institution
    search_fields = [
            'name__icontains',
            ]
    add_form = InstitutionForm
    update_form = InstitutionForm
    list_fields = ['name','city','responsible_for_places', 'cooperational_relationships']
    inlines = [CooperationalRelationshipInlineCRUDView]

class GeonameCRUDView(CRUDView):
    model = Geoname
    search_fields = [
            'name__icontains',
            ]
    list_fields = ['name', 'population']


def get_urls(basepath='',namespace=None):

    return  [
                url(basepath, include(InstitutionCRUDView().get_urls(), namespace=namespace)),
                url(basepath, include(GeonameCRUDView().get_urls(), namespace=namespace)),
                url(basepath, include(CooperationalRelationshipInlineCRUDView().get_urls(), namespace=namespace)),
            ]

Now, when I navigate to http://localhost:8000/crud/institution/1/update , I see the right form:

Screen Shot 2019-11-01 at 13 32 24

However, when I want to choose a city, I cannot type anything:

Screen Shot 2019-11-01 at 13 32 31

Also, I'm getting these errors in the JavaScript-console:

Screen Shot 2019-11-01 at 13 33 51

Non-custom form

I can disable the custom form:

class CooperationalRelationshipInlineCRUDView(InlineAjaxCRUD):
    model = CooperationalRelationship
    base_model = Institution
    inline_field = 'institution'
    title = "Cooperational Relationships"
    list_fields = ['city', 'description', ]
    #add_form = CooperationalRelationshipForm
    #update_form = CooperationalRelationshipForm

But then, the forms takes ages to load (in this example, it's loading 35,000 items into the select) and also the HTML-selects do not seem to be converted to select2-objects.

Screen Shot 2019-11-01 at 13 36 36

Screen Shot 2019-11-01 at 13 36 46

Related issues

I've seen that a number of people have problems with select2 and modals, so I'm linking a few threads I've found:

@benmaier
Copy link
Author

benmaier commented Nov 1, 2019

also paging @kptac , you seem to have edited the inline-template because something else did not work in #inline -- maybe you have some advice on how I could proceed to solve this problem? If not, that's completely fine, too.

@A4TIF
Copy link
Contributor

A4TIF commented Nov 2, 2019

I haven't tested this with your code, but from the console error, you need to serve select2 js from your server instead of cdn as that error seems to be reporting that select2.min.js was blocked because of CORs policy. Also, confirm the jquery version that is required for django-select2. I have not used that before, so not really sure. I think that should resolve it for you (hopefully)

@benmaier
Copy link
Author

benmaier commented Nov 4, 2019

thank you for your answer! I've since found that the CORs policy errors can be resolved by setting the following variables in your project-settings.py:

SELECT2_JS = 'select2/js/select2.min.js'
SELECT2_CSS = 'select2/css/select2.min.css'
SELECT2_I18N_PATH = 'select2/js/i18n'

I've updated my error-example-repository accordingly.

Unfortunately, this does not resolve the original problem and the select2-select is still unusable. Thanks for your answer though!

@benmaier
Copy link
Author

benmaier commented Nov 4, 2019

It turns out that this is a long-known problem:

with an easy quick fix:

(remove the tabindex=-1-attribute from the modal)

For my particular case, adding this line to the <script>-section of templates/cruds/ajax/_form.html sufficed:

$(".modal").removeAttr("tabindex");

I'm leaving this issue open nevertheless, until the solution is implemented. Tell me if I should make a pull-request, but it seems like an easy fix. There's probably a better solution, too. I've read that removing tabindex=-1 from a modal removes the ability to close it with the ESC-key.

@A4TIF
Copy link
Contributor

A4TIF commented Nov 4, 2019

Good find. For the time being, in my opinion, I wouldn't use a modal or the default forms, but a custom form and not load all the entries directly on to the page. Instead, you can easily create an ajax request view, that will return a json response with the entries while users are typing / searching in the select2 js widget. You can read up on that here:

https://select2.org/data-sources/ajax

I have used that in one of my projects before, I can share some of the code for you if you need any assistance with it. Good luck.

@benmaier
Copy link
Author

benmaier commented Nov 4, 2019

Indeed, I'm already using a custom form with an Ajax request to let users search through the entries :) (see my declarations above in the forms-section).

I just wanted to additionally demonstrate that when one uses the default form, the selects are not converted to select2.

cheers

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants