darklow / django-suit

Modern theme for Django admin interface
http://djangosuit.com/
Other
2.33k stars 704 forks source link

`django-select2` doesn't work on inline forms #337

Open antitoxic opened 9 years ago

antitoxic commented 9 years ago

I'm referring to https://github.com/applegrew/django-select2/

I'm using the AutoModelSelect2Field as per example: https://github.com/darklow/django-suit-examples/blob/master/admin.py#L337

Django-select is working with standard forms but not working with inline forms. When a user presses "Add new ...." in inline forms the new inputs copies over from the 0-indexed form which doesnt exactly work because the select2 html is copied but the events are triggered not for the new fields but for the initial 0-indexed form.

Issues i found in research and consider interesting:

darklow commented 9 years ago

See my comment here: https://github.com/darklow/django-suit/issues/309#issuecomment-62850832

antitoxic commented 9 years ago

@darklow this is not the case. I know about the hook. Try it. It gets ugly.

Somehow django-select2 only triggers for the empty-form or existing/extra forms

darklow commented 9 years ago

I don't currently have time to explain every line, but this is how i achieved select2 in inlines in one of my clients project. Here i am duplicating select2 that has ajax autocomplete in it.

Extend: project/templates/admin/project/module/change_form.html

{% extends 'admin/project/change_form.html' %}

{% block extrajs %}
    {{ block.super }}
    <script type="text/javascript">
        $(function () {
            Suit.after_inline.register('init_select2', function (inline_prefix, $row) {
                var i = $row.attr('id').replace(inline_prefix + '-', '');
                var id_ = 'id_' + inline_prefix + '-' + i + '-target';
                var id = '#' + id_;

                $row.find('.select2-container').remove();
                console.info(inline_prefix);

                $(id).data('field_id', $('#id_' + inline_prefix + '-0-target').data('field_id'));
                $(id).change(django_select2.onValChange).data('userGetValText', null);
                $(id).select2({
                    'allowClear': false,
                    'initSelection': django_select2.onInit,
                    'multiple': false, 'minimumInputLength': 2,
                    'minimumResultsForSearch': 6, 'closeOnSelect': false,
                    'width': '280px', 'ajax': {'dataType': 'json', 'quietMillis': 100,
                        'url': '/select2/fields/auto.json',
                        'data': django_select2.runInContextHelper(django_select2.get_url_params, id_),
                        'results': django_select2.runInContextHelper(django_select2.process_results, id_)}, 'placeholder': ''});

            });
        });

    </script>
{% endblock %}

image

antitoxic commented 9 years ago

This looks cool. I am trying to do something like this based on the generated code from django-select2 but this seems better. I am testing it right now.

I'm guessing you ditched the hashed field names that django-select2 generated?

darklow commented 9 years ago

I can't remember in details, since it was a while ago i wrote this code. But basically what i did is checked what JS code is used in single existing inline and on hook replicated it, just with the correct selectors and references. If you use other select2 field then script may vary, but the point would be the same.

antitoxic commented 9 years ago

@darklow i just tested latest master of django-select2 (pip install -e git+https://github.com/applegrew/django-select2.git#egg=django-select2).

It has some improvements. We can now use the following in suit:

$(function () {
    Suit.after_inline.register('init_select2', function (inline_prefix, $row) {
        var i = $row.attr('id').replace(inline_prefix + '-', '');
        $row.find('[data-select2-id]').each(function() {
            var $this = $(this)
            var id = $this.attr('id');
            var key = id.replace('-'+i+'-', '_')
            window.django_select2[key](id, $this.data('select2Id'))
        })
    });
});

And it works for with any fields, with any select2 options that were configured as options for the form widgets in python.

darklow commented 9 years ago

@antitoxic thanks for sharing, these are good news.

banzayats commented 9 years ago

Any updates on this issue? I have the same problem plus I don't see filed label. screen

strayer commented 9 years ago

I had to change the code of @antitoxic a little to make this work with Model/HeavySelect2Widget django-suit 0.2.15 and Django-Select2 5.1.0.

$(function () {
    Suit.after_inline.register('init_select2', function (inline_prefix, $row) {
        $row.find('[data-field_id]').each(function() {

            // Remove generated elements of select2
            $(this).parent().find('span.select2').remove();

            // Reset select2 classes on select
            $(this).removeClass('select2-hidden-accessible');

            // Do the same as django_select2 would do
            // see https://github.com/applegrew/django-select2/blob/5.1.0/django_select2/static/django_select2/django_select2.js
            var field_id = $(this).data('field_id');
            $(this).select2({
                ajax: {
                    data: function (params) {
                        return {
                            term: params.term,
                            page: params.page,
                            field_id: field_id
                        };
                    },
                    processResults: function (data, page) {
                        return {
                            results: data.results
                        };
                    }
                }
            });

        })
    });
});

I also added this CSS since the spans of select2 were messed up too:

.form-horizontal .inline-related .select2 .selection,
.form-horizontal .inline-related .select2 .select2-selection {
    display: block !important;
}

.form-horizontal .inline-related .select2 .dropdown-wrapper {
    display: inline !important;
}

I've only done some quick tests with this, so there still might be some issues. Seems to work fine though.

SalahAdDin commented 9 years ago

:+1:

msi2 commented 8 years ago

to let you know, i found this and it worked for me. I still have to deal with a few css bugs https://gist.github.com/yuchant/d935208978a1fc6e3098

DjThopson commented 6 years ago

It worked for me by adding the following line in the static/suit/js/suit.js

Add:

(function ($) {
    Suit.after_inline.register('init_select2', function(inline_prefix, row){
        $(row).find('select').select2(); 
    });