I’ve ajax code to append “unit menu” based on “product item” selection. When I create a new row, and select an item from “product menu” I expected that the “unit input” of the same row must affect and append the “unit menu” belongs to the selection of the "product item" in the same row.
But I noticed that when a new row created by cloning and I select a product (all the above rows also affect, i.e after product item selection the "unit menu" of the same row and the "unit menu" of the above rows also affected)
- The next code illustrate what I mean....
$(document).ready(function() {
var purchase = $('.purchase-row').last().clone();
let purchaseCount = 0;
$(document).on('click', '.add_item', function() {
var clone = purchase.clone().prop('id', 'product_' + purchaseCount);
// var clone = purchase.clone().prop('class', 'product_' + purchaseCount);
console.log('clone: ', clone);
$(this).prevAll('.purchase-row').first().after(clone.hide());
clone.slideDown('fast');
$('#product_'+ purchaseCount).find('#id_pro-product').removeClass('product').addClass('newProduct');
$('#product_'+ purchaseCount).find('#id_pro-unit').removeClass('unit').addClass('newUnit');
purchaseCount++;
console.log('PURCHASE-COUNT: ', purchaseCount);// $(this).parent().slideUp('fast');
// The next code for reinitialize select2
var $example = $(".js-programmatic-init").select2();
$example.select2();
});
$(document).on('click', '.purchase-minus', function() {
if (purchaseCount == 0) {
// Do nothing.
alert('You can not delete this row' );
} else {
$(this).closest('.purchase-row').remove();
purchaseCount--;
console.log('PURCHASE-COUNT2: ', purchaseCount);
}
});
$(document).on('click', '.purchase-broom', function() {
$(this).closest('.purchase-row').find('input').val('');
});
$(document).on('change', '.product', function(e){
var id = $(this).val();
console.log('CHANGED-PRODUCT: ', id);
$.ajax({
type: 'POST',
url: '{% url "purchases:get_product_unit" %}',
// dataType: 'json',
// async: true,
// cache: false,
data: {
'pro-product': $('.purchase-row select').closest('.product').val(), // this is right
// find('#id_pro-product')
},
success: function (data) {
console.log(
'FROM SUCCESS: ', data['unit'],
);
var values_3 = data['unit'];
// $('#id_pro-unit').text('');
// $('select').closest('.unit').find('select').text('');
$('select').closest('.unit').text('');
if (values_3.length > 0) {
for (var i = 0; i < values_3.length; i++) {
// $('#id_pro-unit').append('<option>' + values_3[i] + '</option>');
$('select').closest('.unit').append('<option>' + values_3[i] + '</option>');
}
}
},
error: function (){
console.log('ERROR with ajax request in Adding Purchase !!!');
},
});
e.preventDefault();
});
- The next image indicates the main row which I want to clone
- The next image indicates an example for creating 2 rows from the main one.
You can notice a bug in the cloning inputs due to using of (select2 plugin),I raised an issue in Select2 forum(but I havegot no answer till now), So I'll ask a new question here about that behavior..
- My view to handle ajax
from django.http import JsonResponse
def get_product_unit(request):
data = {}
product = request.POST.get('pro-product')
if product is not None:
unit = UOM.objects.values('unit__name', 'uom_options', 'unit').filter(product_id=product)
print('purchase not purchase')
else:
unit = []
data['unit'] = [(obj['unit__name']) for obj in unit]
print(
'PRODUCT: ', product,
'UNIT: ', unit,
)
return JsonResponse(data)
- My tries to fix this problem
1- In fact I tried to make a new ajax call for the new cloned row, but I realize that it can solve by the above ajax code (I don't know how). I think if I knew to access the "class and id" of the new row itself
$(document).on('change', '.newProduct', function(e){
var id = $(this).val();
console.log('SUCCESS-CHANGE-PRODUCT-FROM-NEW-CLASS: ', id);
$.ajax({
type: 'POST',
url: '{% url "purchases:get_new_row_unit" %}',
// dataType: 'json',
// async: true,
// cache: false,
data: {
'pro-product': id,
// $('#product_'+purchaseCount).closest('.newProduct select').val(),
// find('#id_pro-product')
},
success: function (data) {
console.log(
'FROM SUCCESS-NEW-CLASS: ', data['unit'],
'PRODUCT-FROM-NEW-CLASS: ', data['product'],
);
var values_3 = data['unit'];
// $('#id_pro-unit').text('');
// $('select').closest('.newUnit').text('');
if (values_3.length > 0) {
for (var i = 0; i < values_3.length; i++) {
// $('#id_pro-unit').append('<option>' + values_3[i] + '</option>');
// $('.newUnit select').closest('#product_'+ purchaseCount).append('<option>' + values_3[i] + '</option>');
// $('select').closest('#product_'+ purchaseCount).find('.newUnit').append('<option>' + values_3[i] + '</option>');
//$('select').closest('.newUnit').append('<option>' + values_3[i] + '</option>');
$('.purchase-row #id_pro-unit').append('<option>' + values_3[i] + '</option>');
}
}
},
error: function (){
console.log('ERROR with ajax request in Adding Purchase-New Class !!!');
},
});
e.preventDefault();
});
});
My view
def get_new_row_unit(request):
data = {}
product = request.POST.get('pro-product')
data['product'] = product
if product is not None:
unit = UOM.objects.values('unit__name', 'uom_options', 'unit').filter(product_id=product)
else:
unit = []
data['unit'] = [(obj['unit__name']) for obj in unit]
print(
'PRODUCT: ', product,
'UNIT: ', unit,
)
return JsonResponse(data)
2- Also I tried to do like this Answer But I failed.
3- Also I follow instructions in this answer But I get the "unit menu" of the main row in all new row when I select an item from the "product menu" in the new row.
My Problem in brief
When I select an item from "product" menu in the first "new cloned row" (or from any new rows)."unit menu" append to all above rows.
What I want to achieve
I want when I select an item from "product menu" only "unit menu" append to the "unit input" of the same row.
I knew that I've missed something but I failed to discover it.
Any suggestions will be appreciated.
=============================================================
My Answer To This Issue After searching and Thinking
=============================================================
Finally I fix my issue as usual (thanks to stackoverflow community). I want to share my solution of this issue. Really it took time to understand how it works and how to access the new row or (in other words "how to access the row inputs itself").
- My Problem in brief : When I select an item from "product" menu in the first "new cloned row" (or from any new rows)."unit menu" append to all above rows.
After searching on the web and searching here in the community questions. I found the next answers are useful and helpful.
And as I said it can be done by one ajax call.
1- In fact I tried to make a new ajax call for the new cloned row, but I realize that it can solve by the above ajax code (I don't know how).
The final code has became as follow
$(document).on('change', '.product', function(e){
var product_id = $(this).val();
let $el = $(this).closest('.purchase-row');
console.log('SUCCESS-CHANGE-PRODUCT: ', product_id,);
$.ajax({
type: 'POST',
url: '{% url "purchases:get_product_unit" %}',
data: {
'pro-product': product_id,
},
success: function (data) {
if (purchaseCount == 0) {
console.log('purchase count equal to ZERO: ');
console.log(
'FROM SUCCESS: ', data['unit'],
);
var values_3 = data['unit'];
if (values_3.length > 0) {
for (var i = 0; i < values_3.length; i++) {
$el.find('.unit').append('<option>' + values_3[i] + '</option>');
}
}
} else {
let unit = $el.find('.newUnit'); // here I can access the "unit input" of the same row of the "product input"
var values_3 = data['unit'];
unit.text('');
console.log('COUNT IS NOT EQUAL TO ZERO:', values_3);
if (values_3.length > 0) {
for (var i = 0; i < values_3.length; i++) {
unit.append('<option>' + values_3[i] + '</option>');
}
}
}
},
error: function (){
console.log('ERROR with ajax request in Adding Purchase !!!');
},
});
e.preventDefault();
});
Also I found some answers about how to copy table row to another table and these answers help me a lot. Here is some of them