diff --git a/myproject/products/templates/products/includes/select2-product-init.html b/myproject/products/templates/products/includes/select2-product-init.html
index c6ea803..5d0ebd2 100644
--- a/myproject/products/templates/products/includes/select2-product-init.html
+++ b/myproject/products/templates/products/includes/select2-product-init.html
@@ -40,10 +40,32 @@
* @param {Element} element - DOM элемент select
* @param {string} type - Тип поиска ('product' или 'variant')
* @param {string} apiUrl - URL API для поиска
+ * @returns {boolean} - true если инициализация прошла успешно, false иначе
*/
window.initProductSelect2 = function(element, type, apiUrl) {
- if (!element || $(element).data('select2')) {
- return; // Уже инициализирован
+ // Валидация входных параметров
+ if (!element) {
+ console.error('initProductSelect2: element is null or undefined');
+ return false;
+ }
+
+ if (!apiUrl || typeof apiUrl !== 'string') {
+ console.error('initProductSelect2: invalid apiUrl', apiUrl);
+ return false;
+ }
+
+ // Проверка загрузки jQuery и Select2
+ if (typeof $ === 'undefined' || typeof $.fn.select2 === 'undefined') {
+ console.error('initProductSelect2: jQuery or Select2 not loaded');
+ return false;
+ }
+
+ var $element = $(element);
+
+ // Улучшенная проверка инициализации
+ if ($element.hasClass('select2-hidden-accessible')) {
+ console.log('initProductSelect2: already initialized, skipping', element.name);
+ return true; // Уже инициализирован - это не ошибка
}
var placeholders = {
@@ -51,38 +73,45 @@
'variant': 'Начните вводить название группы...'
};
- $(element).select2({
- theme: 'bootstrap-5',
- placeholder: placeholders[type] || 'Выберите...',
- allowClear: true,
- width: '100%',
- language: 'ru',
- minimumInputLength: 0,
- dropdownAutoWidth: false,
- ajax: {
- url: apiUrl,
- dataType: 'json',
- delay: 250,
- data: function (params) {
- return {
- q: params.term || '',
- type: type,
- page: params.page || 1
- };
+ try {
+ $element.select2({
+ theme: 'bootstrap-5',
+ placeholder: placeholders[type] || 'Выберите...',
+ allowClear: true,
+ width: '100%',
+ language: 'ru',
+ minimumInputLength: 0,
+ dropdownAutoWidth: false,
+ ajax: {
+ url: apiUrl,
+ dataType: 'json',
+ delay: 250,
+ data: function (params) {
+ return {
+ q: params.term || '',
+ type: type,
+ page: params.page || 1
+ };
+ },
+ processResults: function (data) {
+ return {
+ results: data.results,
+ pagination: {
+ more: data.pagination.more
+ }
+ };
+ },
+ cache: true
},
- processResults: function (data) {
- return {
- results: data.results,
- pagination: {
- more: data.pagination.more
- }
- };
- },
- cache: true
- },
- templateResult: formatSelectResult,
- templateSelection: formatSelectSelection
- });
+ templateResult: formatSelectResult,
+ templateSelection: formatSelectSelection
+ });
+ console.log('initProductSelect2: successfully initialized for', element.name);
+ return true;
+ } catch (error) {
+ console.error('initProductSelect2: initialization error', error);
+ return false;
+ }
};
/**
diff --git a/myproject/products/templates/products/variantgroup_form.html b/myproject/products/templates/products/variantgroup_form.html
index c0e0c6d..e46e8ad 100644
--- a/myproject/products/templates/products/variantgroup_form.html
+++ b/myproject/products/templates/products/variantgroup_form.html
@@ -215,12 +215,43 @@ document.addEventListener('DOMContentLoaded', function() {
const totalFormsInput = document.querySelector('[name$="TOTAL_FORMS"]');
const apiUrl = '{% url "products:api-search-products-variants" %}';
+ // Валидация
+ if (!container) {
+ console.error('items-tbody container not found');
+ return;
+ }
+
+ if (!totalFormsInput) {
+ console.error('TOTAL_FORMS input not found');
+ return;
+ }
+
+ if (!apiUrl || apiUrl.includes('undefined')) {
+ console.error('Invalid API URL:', apiUrl);
+ return;
+ }
+
+ console.log('Initializing variant group form with API URL:', apiUrl);
+
// Инициализируем Select2 для всех селектов товаров
function initSelect2ForRow(row) {
- const productSelect = row.querySelector('[name$="-product"]');
- if (productSelect) {
- window.initProductSelect2(productSelect, 'product', apiUrl);
+ if (!row) {
+ console.error('initSelect2ForRow: row is null');
+ return false;
+ }
+ const productSelect = row.querySelector('[name$="-product"]');
+ if (!productSelect) {
+ console.warn('initSelect2ForRow: product select not found in row');
+ return false;
+ }
+
+ // Убираем старые обработчики перед повторной инициализацией
+ $(productSelect).off('select2:select');
+
+ const success = window.initProductSelect2(productSelect, 'product', apiUrl);
+
+ if (success) {
// Обработчик события при выборе товара
$(productSelect).on('select2:select', function(e) {
// Извлекаем числовой ID из формата "product_123"
@@ -239,13 +270,20 @@ document.addEventListener('DOMContentLoaded', function() {
}
updateRowData(row);
});
+ return true;
+ } else {
+ console.error('initSelect2ForRow: failed to initialize Select2');
+ return false;
}
}
// Функция для обновления данных строки при выборе товара
function updateRowData(row) {
+ if (!row) return;
+
const productSelect = row.querySelector('[name$="-product"]');
if (!productSelect || !productSelect.value) {
+ // Сброс данных
row.querySelector('[data-product-sku]').textContent = '-';
row.querySelector('[data-product-price]').textContent = '-';
row.querySelector('[data-product-stock]').innerHTML = '-';
@@ -262,13 +300,26 @@ document.addEventListener('DOMContentLoaded', function() {
// Получаем цену и статус через AJAX (используем числовой ID)
const numericId = productSelect.value;
- fetch(`{% url "products:api-search-products-variants" %}?id=${numericId}`)
- .then(response => response.json())
+
+ // Добавляем timeout для fetch
+ const controller = new AbortController();
+ const timeoutId = setTimeout(() => controller.abort(), 5000);
+
+ fetch(`${apiUrl}?id=${numericId}`, { signal: controller.signal })
+ .then(response => {
+ clearTimeout(timeoutId);
+ if (!response.ok) {
+ throw new Error(`HTTP error! status: ${response.status}`);
+ }
+ return response.json();
+ })
.then(data => {
if (data.results && data.results.length > 0) {
const product = data.results[0];
row.querySelector('[data-product-sku]').textContent = product.sku || sku;
- row.querySelector('[data-product-price]').innerHTML = `${product.price} руб.` || '-';
+
+ const price = product.price || product.actual_price || '0';
+ row.querySelector('[data-product-price]').innerHTML = `${price} руб.`;
// Отображаем статус наличия
const stockCell = row.querySelector('[data-product-stock]');
@@ -277,21 +328,33 @@ document.addEventListener('DOMContentLoaded', function() {
} else {
stockCell.innerHTML = ' Нет';
}
+ } else {
+ // Fallback: используем данные из опции
+ row.querySelector('[data-product-sku]').textContent = sku;
+ row.querySelector('[data-product-price]').textContent = '-';
+ row.querySelector('[data-product-stock]').textContent = '-';
}
})
- .catch(() => {
+ .catch(error => {
+ clearTimeout(timeoutId);
+ console.error('updateRowData: fetch error', error);
+ // Fallback: данные из опции
row.querySelector('[data-product-sku]').textContent = sku;
row.querySelector('[data-product-price]').textContent = '-';
row.querySelector('[data-product-stock]').textContent = '-';
});
}
- // Инициализируем для существующих строк
- container.querySelectorAll('.item-row').forEach(row => {
- initSelect2ForRow(row);
- // Загружаем данные товара при загрузке страницы (с небольшой задержкой)
- setTimeout(() => updateRowData(row), 100);
- });
+ // Инициализируем для существующих строк с небольшой задержкой
+ setTimeout(function() {
+ container.querySelectorAll('.item-row').forEach(row => {
+ const success = initSelect2ForRow(row);
+ if (success) {
+ // Загружаем данные только если Select2 инициализирован
+ setTimeout(() => updateRowData(row), 200);
+ }
+ });
+ }, 100);
// ДОБАВЛЕНИЕ НОВОГО ТОВАРА
document.getElementById('add-item-btn').addEventListener('click', function(e) {
@@ -342,8 +405,17 @@ document.addEventListener('DOMContentLoaded', function() {
// Увеличиваем счетчик форм
totalFormsInput.value = newFormIndex + 1;
- // Инициализируем Select2 для нового селекта
- initSelect2ForRow(newRow);
+ // Даем время браузеру отрисовать элемент перед инициализацией Select2
+ setTimeout(function() {
+ const success = initSelect2ForRow(newRow);
+ if (!success) {
+ console.error('Failed to initialize Select2 for new row, retrying...');
+ // Повторная попытка через 500ms
+ setTimeout(function() {
+ initSelect2ForRow(newRow);
+ }, 500);
+ }
+ }, 50);
// Обновляем приоритеты
updatePriorities();