Как прикрепить обратный вызов к рекурсивно сгенерированному выпадающему списку <select>? - PullRequest
2 голосов
/ 29 сентября 2019

Я пытаюсь реализовать цепочечный зависимый выпадающий список выпадающего списка, поэтому вы начинаете с одного выпадающего списка для основной категории, и как только вы выбираете основную категорию, появляется другой <select> для выбора подкатегории и т. Д. До самого внутреннего (наиболее конкретного) категория выбрана. Код, который у меня есть в настоящее время, работает только для одной подкатегории (прямые дочерние), как я могу заставить его работать и для других уровней? Итак, мне нужно каким-то образом прикрепить обратный вызов onChange к вновь созданному <select>.

Это код jQuery в моем шаблоне Django:

{% extends 'pages/base.html' %}

{% block content %}
<h1>Create a product</h1>
<form method='POST' id='productForm' data-products-url="{% url 'products:ajax_load_categories' %}">
    {{ form.as_p }}
</form>
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
<script>
    $("select").change(function () {
      var url = $("#productForm").attr("data-products-url");
      var categoryId = $(this).val();

      $.ajax({                       
        url: url,                    
        data: {
          'category': categoryId
        },
        success: function (data) {
          $("#productForm").append(data);
        }
      });
    });
</script>
{% endblock %}

Вот мой взгляд:

def load_categories(request):
    category_id = request.GET.get('category')
    subcategories = Category.objects.get(id=category_id).get_children()
    return render(request, 'products/category_dropdown_list_options.html', {'subcategories': subcategories})

products/category_dropdown_list_options.html

<select id="select_{{ subcategories.first.get_level }}">
    <option value="">---------</option>
    {% for subcategory in subcategories %}
        <option value="{{ subcategory.pk }}">{{ subcategory.name }}</option>
    {% endfor %}
</select>

Вот моя urls.py:

app_name = 'products'
urlpatterns = [
    path('create/', product_create_view, name='product-create'),
    path('ajax/load-categories/', load_categories, name='ajax_load_categories')
]

Вот моя модель категории согласно запросу:

from mptt.models import MPTTModel, TreeForeignKey

class Category(MPTTModel):
    parent = TreeForeignKey('self', on_delete=models.CASCADE, null=True, blank=True, related_name='children')
    name = models.CharField(max_length=255)
    slug = models.SlugField()

    class Meta:
        unique_together = (('parent', 'slug',))
        verbose_name_plural = 'categories'

    class MPTTMeta:
        order_insertion_by = ['name']

    def __str__(self):
        return self.name

    def save(self, *args, **kwargs):
        self.slug = slugify(self.name)
        super().save(*args, **kwargs)

    def get_slug_list(self):
        ancestors = self.get_ancestors(include_self=True)
        slugs = [ancestor.slug for ancestor in ancestors]
        new_slugs = []
        for idx, ancestor in enumerate(slugs, 1):
            new_slugs.append('/'.join(slugs[:idx]))
        return new_slugs

    def get_recursive_product_count(self):
        return Product.objects.filter(category__in=self.get_descendants(include_self=True)).count()

1 Ответ

1 голос
/ 29 сентября 2019

Вам нужно будет превратить ваш jQuery ajax-скрипт в функцию, а затем вызвать ее рекурсивно , например:

<script>
    var $r_ = function() {
        var url = $("#productForm").attr("data-products-url");
        var categoryId = $(this).val();
        $.ajax({                       
          url: url,                    
          data: {
            'category': categoryId
          },
          success: function (data) {
            if (data != 'leaf_node') {
              $("#productForm").append(data);
            }
            $('select').change($r_);
          }
        });

    } //end of $r_

    $('select').change($r_);
</script>

Обновление

Если вы возьметеВзглянув на метод get_children модели MPTT, вы увидите, что он проверяет, есть ли у экземпляра какие-либо дочерние элементы, и возвращает None, если его нет.

ДобавитьNone проверьте ваше представление, затем добавьте другой ответ, когда вы достигли конечного узла :

from django.http import HttpResponse

def load_categories(request):
    category_id = request.GET.get('category')
    subcategories = Category.objects.get(id=category_id).get_children()
    if subcategories:
        return render(request, 'products/category_dropdown_list_options.html', {'subcategories': subcategories})

    return HttpResponse('leaf_node')

Затем добавьте проверку для конечных узлов в вашем вызове ajax (см. выше).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...