Django FormSet Dynamic Add/удаление не работает для цветов, размеров и изображенийHtml

Программисты Html
Ответить
Anonymous
 Django FormSet Dynamic Add/удаление не работает для цветов, размеров и изображений

Сообщение Anonymous »

Заявление о проблеме
Я работаю над формой django , где пользователи могут динамически добавлять/удалить colors , размеры и Images при добавлении продукта.
  • a продукт может иметь несколько цветов .
  • Каждый color < /strong> может иметь несколько размеров .
  • Каждый color может иметь множество изображений .
    Пользователи должны иметь возможность динамически Добавить/удалить цвета, размеры и изображения с использованием javascript.
ожидаемое поведение
  • Нажмите «Добавить цвет» должна создать новую форму цвета с собственными размер размер и разделения изображений .
  • Нажмите "Добавить Размер " внутри цвета должен добавить новый размер только к этому конкретному цвету. Этот конкретный цвет.
  • Нажмите «Удалить цвет» должен удалить конкретный цветовой раздел.
ток Проблема
  • только кнопка «Удалить цвет» работает.
  • Код: Выделить всё

    "Add Color"
    , "добавить size" и "добавить image" кнопки не работают. Кнопки. Forms < /strong> (они существуют).

    ✔ Проверенные слушатели событий прикреплены с использованием console.log () < /code>.

    ✔ обеспечить клоненод (true) < /код> правильно копирует элементы.

    ✔ проверено на ошибки JavaScript в консоли (без ошибок синтаксиса). < /p>

    django forms & formsets

    forms (forms.py)

    from django import forms
    from django.forms import inlineformset_factory
    from .models import VendorProduct, ProductColor, ProductSize, ProductImage, ColorImage

    class ProductForm(forms.ModelForm):
    class Meta:
    model = VendorProduct
    fields = ['title', 'category', 'base_price']
    widgets = {
    'title': forms.TextInput(attrs={'class': 'form-control'}),
    'category': forms.Select(attrs={'class': 'form-control'}),
    'base_price': forms.NumberInput(attrs={'class': 'form-control'}),
    }

    class ProductColorForm(forms.ModelForm):
    class Meta:
    model = ProductColor
    fields = ['color_name', 'color_code']
    widgets = {
    'color_name': forms.TextInput(attrs={'class': 'form-control'}),
    'color_code': forms.TextInput(attrs={'class': 'form-control'}),
    }

    class ProductSizeForm(forms.ModelForm):
    class Meta:
    model = ProductSize
    fields = ['size_name', 'stock', 'price_increment']
    widgets = {
    'size_name': forms.TextInput(attrs={'class': 'form-control'}),
    'stock': forms.NumberInput(attrs={'class': 'form-control'}),
    'price_increment': forms.NumberInput(attrs={'class': 'form-control'}),
    }

    class ProductImageForm(forms.ModelForm):
    class Meta:
    model = ProductImage
    fields = ['image']
    widgets = {
    'image': forms.FileInput(attrs={'class': 'form-control'}),
    }

    class ColorImageForm(forms.ModelForm):
    class Meta:
    model = ColorImage
    fields = ['image']
    widgets = {
    'image': forms.FileInput(attrs={'class': 'form-control'}),
    }

    # Formsets
    ProductColorFormSet = inlineformset_factory(VendorProduct, ProductColor, form=ProductColorForm, extra=1, can_delete=True)
    ProductImageFormSet = inlineformset_factory(VendorProduct, ProductImage, form=ProductImageForm, extra=1, can_delete=True)
    ProductSizeFormSet = inlineformset_factory(ProductColor, ProductSize, form=ProductSizeForm, extra=1, can_delete=True)
    ColorImageFormSet = inlineformset_factory(ProductColor, ColorImage, form=ColorImageForm, extra=1, can_delete=True)
    < /code>

    шаблон HTML (add_product.html) < /strong> < /h3>

    {% csrf_token %}
    {{ form.as_p }}

    {% for color_form in color_formset %}

    {{ color_form.color_name.label_tag }}
    {{ color_form.color_name }}

    {{ color_form.color_code.label_tag }}
    {{ color_form.color_code }}


    Color Images
    {{ color_image_formset.management_form }}
    {% for image_form in color_image_formset %}

    {{ image_form.image }}

    {% endfor %}
    Add Image



    Sizes


    {{ size_formset.management_form }}
    {% for size_form in size_formset %}

    {{ size_form.size_name.label_tag }}
    {{ size_form.size_name }}

    {{ size_form.stock.label_tag }}
    {{ size_form.stock }}

    {{ size_form.price_increment.label_tag }}
    {{ size_form.price_increment }}

    {% endfor %}


    Add Size
    Remove Color

    {% endfor %}


    Add Color
    Save

    < /code>

    javascript (dynamic.js) < /strong> < /h3>
    document.addEventListener("DOMContentLoaded", function () {
    // Initialize indexes
    let colorIndex = parseInt(document.querySelector('[name="colors-TOTAL_FORMS"]')?.value) || 0;
    let imageIndex = parseInt(document.querySelector('[name="images-TOTAL_FORMS"]')?.value) || 0;

    function addColor() {
    let colorContainer = document.getElementById("colorContainer");
    let totalForms = document.querySelector('[name="colors-TOTAL_FORMS"]');

    if (!totalForms) {
    console.error("Management form for colors-TOTAL_FORMS not found!");
    return;
    }

    let newColor = document.querySelector(".color-item").cloneNode(true);
    newColor.querySelectorAll("input, select").forEach(input => {
    if (input.name) {
    input.name = input.name.replace(/colors-\d+/g, `colors-${colorIndex}`);
    input.removeAttribute("id"); // Remove duplicate IDs
    input.value = ""; // Clear input values
    }
    });

    // Attach event listeners to the new color block
    newColor.querySelector(".remove-btn").addEventListener("click", function () {
    removeColor(this);
    });

    newColor.querySelector(".add-size-btn").addEventListener("click", function () {
    addSize(this);
    });

    colorContainer.appendChild(newColor);
    totalForms.value = colorIndex + 1; // Update Django formset tracker
    colorIndex++;
    }

    function addSize(button) {
    let sizeContainer = button.closest(".color-item").querySelector(".sizeContainer");
    let sizeIndex = sizeContainer.querySelectorAll(".size-item").length;

    let newSize = sizeContainer.querySelector(".size-item").cloneNode(true);
    newSize.querySelectorAll("input, select").forEach(input => {
    if (input.name) {
    input.name = input.name.replace(/sizes-\d+/g, `sizes-${sizeIndex}`);
    input.removeAttribute("id");
    input.value = ""; // Clear input values
    }
    });

    sizeContainer.appendChild(newSize);
    }

    function removeColor(button) {
    let colorItem = button.closest(".color-item");
    colorItem.remove();

    // Update colors-TOTAL_FORMS count
    colorIndex--;
    document.querySelector('[name="colors-TOTAL_FORMS"]').value = colorIndex;
    }

    function addImage() {
    let imageContainer = document.getElementById("imageContainer");
    let totalForms = document.querySelector('[name="images-TOTAL_FORMS"]');

    if (!totalForms) {
    console.error("Management form for images-TOTAL_FORMS not found!");
    return;
    }

    let newImage = document.querySelector(".image-item").cloneNode(true);
    newImage.querySelectorAll("input").forEach(input => {
    if (input.name) {
    input.name = input.name.replace(/images-\d+/g, `images-${imageIndex}`);
    input.removeAttribute("id");
    input.value = ""; // Clear input values
    }
    });

    imageContainer.appendChild(newImage);
    totalForms.value = imageIndex + 1; // Update Django formset tracker
    imageIndex++;
    }

    // Attach event listeners dynamically
    document.getElementById("addColorButton")?.addEventListener("click", addColor);
    document.getElementById("addImageButton")?.addEventListener("click", addImage);

    // Attach existing remove/add-size event listeners for initial elements
    document.querySelectorAll(".remove-btn").forEach(button => {
    button.addEventListener("click", function () {
    removeColor(this);
    });
    });

    document.querySelectorAll(".add-size-btn").forEach(button => {
    button.addEventListener("click", function () {
    addSize(this);
    });
    });
    });
    < /code>

    Сводка проблем < /strong> < /h3>

    Слушатели событий не были прикреплены правильно. Strong> JavaScript не использовал делегирование событий должным образом.
  • Сценарий, необходимый для обработки как статических, так и динамически добавленных элементов.


Подробнее здесь: https://stackoverflow.com/questions/794 ... and-images
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «Html»