最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - On the frontend the Select2 is not populating the fields for the user to select - Stack Overflow

programmeradmin0浏览0评论

I have an invoiceform to collect the date for postgresql database and Im having trouble with endpoints working properly and populating the drop down list for Salesman field and Product name field.

I checked the json response and it is providing the frontend with with sets whereas with my other backend code although the json responses were valid the select2 couldn't populate then retain the typed out name in the field.

Frontend

// Initialize Select2 components
$(document).ready(function() {
  $('#salesman').select2({
    placeholder: 'Select Salesman',
    ajax: {
      url: '/api/salesmen',
      dataType: 'json',
      delay: 250,
      processResults: data => ({
        results: data
      })
    }
  });
  initProductSelect($('.product-row').first().find('.product-name'));
});

function initProductSelect(element) {
  element.select2({
    placeholder: 'Select Product',
    ajax: {
      url: '/api/products',
      dataType: 'json',
      delay: 250,
      processResults: data => ({
        results: data
      })
    }
  }).on('select2:select', async function(e) {
    const row = $(this).closest('.product-row');
    try {
      const response = await fetch(`/api/product/${e.params.data.id}`);
      const product = await response.json();
      row.data('conversion', product.conversion_rate)
        .find('.stock-ctn, .added-ctn, .return-ctn').attr('placeholder', product.primary_unit)
        .closest('tr').find('.total-dispatch-ctn, .sold-ctn').text(`0 ${product.primary_unit}`);
    } catch (error) {
      console.error('Error loading product:', error);
    }
  });
}

function convertToPieces(ctn, pcs, row) {
  return (ctn * row.data('conversion')) + (parseInt(pcs) || 0);
}

function updateTotalDispatch(row) {
  const $row = $(row);
  const conversion = $row.data('conversion') || 1;
  const stockCtn = parseInt($row.find('.stock-ctn').val()) || 0;
  const stockPcs = parseInt($row.find('.stock-pcs').val()) || 0;
  const addedCtn = parseInt($row.find('.added-ctn').val()) || 0;
  const addedPcs = parseInt($row.find('.added-pcs').val()) || 0;
  const totalPieces = (stockCtn + addedCtn) * conversion + stockPcs + addedPcs;

  $row.find('.total-dispatch-ctn').text(`${Math.floor(totalPieces/conversion)} ${$row.find('.stock-ctn').attr('placeholder')}`);
  $row.find('.total-dispatch-pcs').text(`${totalPieces % conversion} Pcs`);
}

function updateSoldStock(row) {
  const $row = $(row);
  const conversion = $row.data('conversion') || 1;

  // Parse inputs with fallback to 0 if empty or invalid
  const stockCtn = parseInt($row.find('.stock-ctn').val()) || 0;
  const stockPcs = parseInt($row.find('.stock-pcs').val()) || 0;
  const addedCtn = parseInt($row.find('.added-ctn').val()) || 0;
  const addedPcs = parseInt($row.find('.added-pcs').val()) || 0;
  const returnCtn = parseInt($row.find('.return-ctn').val()) || 0;
  const returnPcs = parseInt($row.find('.return-pcs').val()) || 0;

  // Calculate total stock and return
  const totalStock = (stockCtn + addedCtn) * conversion + (stockPcs + addedPcs);
  const totalReturn = returnCtn * conversion + returnPcs;

  // Validate return doesn't exceed stock
  if (totalReturn > totalStock) {
    const maxReturn = totalStock;
    $row.find('.return-ctn').val(Math.floor(maxReturn / conversion));
    $row.find('.return-pcs').val(maxReturn % conversion);
    alert("Return exceeds available stock!");
    return;
  }

  // Calculate sold stock
  const soldPcs = totalStock - totalReturn;
  const soldCtn = Math.floor(soldPcs / conversion);
  const soldRemainingPcs = soldPcs % conversion;

  // Update display
  $row.find('.sold-ctn').text(`${soldCtn} ${$row.find('.stock-ctn').attr('placeholder')}`);
  $row.find('.sold-pcs').text(`${soldRemainingPcs} Pcs`);

  // Disable "Add Rate" button if all stock is allocated
  let totalAllocated = 0;
  $row.find('.rate-rows tr').each(function() {
    const rateCtn = parseInt($(this).find('.rate-ctn').val()) || 0;
    const ratePcs = parseInt($(this).find('.rate-pcs').val()) || 0;
    totalAllocated += rateCtn * conversion + ratePcs;
  });

  $row.find('.add-rate').prop('disabled', totalAllocated >= soldPcs);
}

function addRate(button) {
  const row = $(button).closest('.product-row');
  const rateRows = row.find('.rate-rows');
  const soldPcs = convertToPieces(
    parseInt(row.find('.sold-ctn').text()),
    parseInt(row.find('.sold-pcs').text()),
    row
  );

  let totalAllocated = 0;
  rateRows.find('tr').each(function() {
    totalAllocated += convertToPieces(
      parseInt($(this).find('.rate-ctn').val()),
      parseInt($(this).find('.rate-pcs').val()),
      row
    );
  });

  if (totalAllocated >= soldPcs) {
    alert("Allocated quantity exceeds sold stock!");
    return;
  }

  const newRow = $('<tr>').html(`
                <td>
                    <div class="rate-qty-inputs">
                        <input type="number" class="rate-ctn" min="0" placeholder="Unit">
                        <span>-</span>
                        <input type="number" class="rate-pcs" min="0" placeholder="Pcs">
                    </div>
                </td>
                <td><input type="number" class="rate-value" min="0" step="0.01" placeholder="रू"></td>
                <td>${rateRows.children().length === 0 ? 
                    '<input type="checkbox" class="rate-all" onchange="selectAllQuantity(this)">' : ''}
                </td>
            `);
  rateRows.append(newRow);
  updateSoldStock(row);
}

function removeRate(button) {
  const row = $(button).closest('.product-row');
  const rateRows = row.find('.rate-rows');
  const lastRateRow = rateRows.find('tr').last();

  if (lastRateRow.length > 0) {
    lastRateRow.remove(); // Remove the last rate row
    updateSoldStock(row); // Update sold stock after removal
  } else {
    alert("No rate rows to remove!");
  }
}

function selectAllQuantity(checkbox) {
  const row = $(checkbox).closest('.product-row');
  const rateRow = $(checkbox).closest('tr');
  const conversion = row.data('conversion');
  const soldCtn = parseInt(row.find('.sold-ctn').text());
  const soldPcs = parseInt(row.find('.sold-pcs').text());

  if (checkbox.checked) {
    rateRow.find('.rate-ctn').val(soldCtn).prop('disabled', true);
    rateRow.find('.rate-pcs').val(soldPcs).prop('disabled', true);
  } else {
    rateRow.find('.rate-ctn, .rate-pcs').val('').prop('disabled', false);
  }
}

function addProductRow() {
  const newRow = $('.product-row').first().clone();
  newRow.find('input').val('');
  newRow.find('.select2-product').remove();
  newRow.find('td:first').html('<select class="product-name select2-product"></select>');
  newRow.find('.serial-number').text($('.product-row').length + 1);
  newRow.find('.rate-rows').empty();
  newRow.find('.total-amount, .sold-ctn, .sold-pcs, .total-dispatch-ctn, .total-dispatch-pcs').text('0');
  $('#products > tbody').append(newRow);
  initProductSelect(newRow.find('.product-name'));
  updateSerialNumbers();
}

function removeProductRow(button) {
  const rows = $('.product-row');
  if (rows.length === 1) {
    rows.find('input').val('');
    rows.find('.rate-rows').empty();
    rows.find('.select2-product').val(null).trigger('change');
    updateSoldStock(rows);
    updateTotalDispatch(rows);
  } else {
    $(button).closest('.product-row').remove();
  }
  updateSerialNumbers();
}

function updateSerialNumbers() {
  $('.product-row .serial-number').each((i, el) => $(el).text(i + 1));
}

function calculateTotal() {
  let grandTotal = 0;
  $('.product-row').each(function() {
    let rowTotal = 0;
    $(this).find('.rate-rows tr').each(function() {
      const ctn = parseInt($(this).find('.rate-ctn').val()) || 0;
      const pcs = parseInt($(this).find('.rate-pcs').val()) || 0;
      const rate = parseFloat($(this).find('.rate-value').val()) || 0;
      const conversion = $(this).closest('.product-row').data('conversion') || 1;
      rowTotal += ((ctn * conversion) + pcs) * rate;
    });
    $(this).find('.total-amount').text(`रू ${rowTotal.toFixed(2)}`);
    grandTotal += rowTotal;
  });
  $('#grand-total').text(`रू ${grandTotal.toFixed(2)}`);
}

async function saveChallan() {
  const challanData = {
    date: $('#date').val(),
    miti: $('#challanMiti').val(),
    challan_no: $('#challanNo').val(),
    salesman_id: $('#salesman').val(),
    items: [],
    total_amount: parseFloat($('#grand-total').text().replace('रू ', ''))
  };

  $('.product-row').each(function() {
    const $row = $(this);
    const item = {
      product_id: $row.find('.product-name').val(),
      stock_van: {
        ctn: parseInt($row.find('.stock-ctn').val()) || 0,
        pcs: parseInt($row.find('.stock-pcs').val()) || 0
      },
      stock_added: {
        ctn: parseInt($row.find('.added-ctn').val()) || 0,
        pcs: parseInt($row.find('.added-pcs').val()) || 0
      },
      stock_return: {
        ctn: parseInt($row.find('.return-ctn').val()) || 0,
        pcs: parseInt($row.find('.return-pcs').val()) || 0
      },
      rates: []
    };

    $row.find('.rate-rows tr').each(function() {
      item.rates.push({
        ctn: parseInt($(this).find('.rate-ctn').val()) || 0,
        pcs: parseInt($(this).find('.rate-pcs').val()) || 0,
        rate: parseFloat($(this).find('.rate-value').val()) || 0
      });
    });

    challanData.items.push(item);
  });

  try {
    const response = await fetch('/api/challan', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json'
      },
      body: JSON.stringify(challanData)
    });
    const result = await response.json();
    alert(result.message);
    if (response.ok) cancelForm();
  } catch (error) {
    console.error('Error:', error);
    alert('Error saving challan');
  }
}

function cancelForm() {
  $('#salesman').val(null).trigger('change');
  $('#date, #challanMiti, #challanNo').val('');
  $('.product-row').each(function(index) {
    if (index > 0) $(this).remove();
    else {
      $(this).find('input').val('');
      $(this).find('.rate-rows').empty();
      $(this).find('.select2-product').val(null).trigger('change');
      $(this).find('.total-amount, .sold-ctn, .sold-pcs, .total-dispatch-ctn, .total-dispatch-pcs').text('0');
    }
  });
  $('#grand-total').text('रू 0.00');
  updateSerialNumbers();
}

// Event listeners for dynamic updates
$('#products').on('input', 'input', function() {
  const row = $(this).closest('.product-row');
  updateTotalDispatch(row);
  updateSoldStock(row);
});
@import url(':wght@300;400;500&display=swap');

body {
  font-family: 'Roboto', sans-serif;
  margin: 20px;
  font-size: 14px;
  color: #333;
  background-color: beige;
}

.header {
  margin-bottom: 20px;
  background-color: white;
  padding: 15px;
  border-radius: 8px;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}

.center-title {
  text-align: center;
  margin: 5px 0;
}

h2 {
  font-size: 18px;
  font-weight: 500;
}

h3,
h4 {
  font-size: 16px;
  font-weight: 400;
}

table {
  width: 70%;
  border-collapse: collapse;
  margin-top: 10px;
  background-color: white;
  border-radius: 8px;
  overflow: hidden;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}

th,
td {
  border: 1px solid #ddd;
  padding: 8px;
  text-align: left;
  font-size: 13px;
}

th {
  background-color: #f2f2f2;
  font-weight: 500;
}

input[type="text"],
input[type="number"],
input[type="date"] {
  border: 1px solid #ccc;
  padding: 5px;
  border-radius: 4px;
  font-size: 13px;
  background-color: #f9f9f9;
}

input:focus {
  border-color: #007BFF;
  outline: none;
  background-color: white;
}

.total-row {
  font-weight: bold;
  text-align: right;
}

.buttons {
  margin-top: 20px;
  display: flex;
  gap: 10px;
}

button {
  padding: 4px 8px;
  font-size: 13px;
  border: none;
  border-radius: 4px;
  background-color: #007BFF;
  color: white;
  cursor: pointer;
  transition: background-color 0.3s ease;
}

button:hover {
  background-color: #0056b3;
}

.total-amount {
  font-weight: bold;
  color: #007BFF;
}

.stock-inputs,
.added-inputs,
.return-inputs,
.rate-qty-inputs {
  display: flex;
  gap: 5px;

  align-items: center;
}

.rate-table {
  width: 100%;
  margin-top: 10px;
  border-collapse: collapse;
}

.rate-table th,
.rate-table td {
  border: 1px solid #ddd;
  padding: 5px;
  font-size: 12px;
}

.rate-table th {
  background-color: #f2f2f2;
}

.stacked {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
}

.stacked span {
  display: block;
  text-align: center;
}

.select2-container {
  width: 200px !important;
  margin-bottom: 5px;
}

.select2-product {
  width: 180px !important;
}

/* Fix for button spacing */
.product-row td:last-child {
  display: flex;
  gap: 5px;
  /* Adds spacing between buttons */
}

/* Style for Add Rate and Remove Rate buttons */
.add-rate,
.remove-rate {
  margin-right: 5px;
  /* Adds spacing between buttons */
}
<link href="/[email protected]/dist/css/select2.min.css" rel="stylesheet" />

<div class="header">
  <h2 class="center-title"> Store</h2>
  <h3 class="center-title">Bau</h3>
  <h4 class="center-title">Daily Challan</h4>
  <div>
    <label>Salesman Name: <select id="salesman" class="select2-salesman"></select></label>
    <label>Challan Date: <input type="date" id="date"></label>
    <label>Challan Miti: <input type="text" id="challanMiti" placeholder="YYYY-MM-DD (Nepali)"></label>
    <label>Challan No: <input type="text" id="challanNo"></label>
  </div>
</div>

<table id="products">
  <thead>
    <tr>
      <th>S.No.</th>
      <th>Product Name</th>
      <th>Stock in Van (Unit/Pcs)</th>
      <th>Stock Added (Unit/Pcs)</th>
      <th>Stock Return (Unit/Pcs)</th>
      <th>Total Dispatch</th>
      <th>Stock Sold (Unit/Pcs)</th>
      <th>Rate per Unit (रू)</th>
      <th>Total Amount (रू)</th>
      <th>Actions</th>
    </tr>
  </thead>
  <tbody>
    <tr class="product-row">
      <td class="serial-number">1</td>
      <td><select class="product-name select2-product"></select></td>
      <td>
        <div class="stock-inputs">
          <input type="number" class="stock-ctn" min="0" placeholder="Unit">
          <span>-</span>
          <input type="number" class="stock-pcs" min="0" placeholder="Pcs">
        </div>
      </td>
      <td>
        <div class="added-inputs">
          <input type="number" class="added-ctn" min="0" placeholder="Unit">
          <span>-</span>
          <input type="number" class="added-pcs" min="0" placeholder="Pcs">
        </div>
      </td>
      <td>
        <div class="return-inputs">
          <input type="number" class="return-ctn" min="0" placeholder="Unit">
          <span>-</span>
          <input type="number" class="return-pcs" min="0" placeholder="Pcs">
        </div>
      </td>
      <td class="total-dispatch">
        <div class="stacked">
          <span class="total-dispatch-ctn">0 Unit</span>
          <span class="total-dispatch-pcs">0 Pcs</span>
        </div>
      </td>
      <td class="sold-stock">
        <div class="stacked">
          <span class="sold-ctn">0 Unit</span>
          <span class="sold-pcs">0 Pcs</span>
        </div>
      </td>
      <td>
        <table class="rate-table">
          <thead>
            <tr>
              <th>Quantity (Unit/Pcs)</th>
              <th>Rate (रू)</th>
              <th>All</th>
            </tr>
          </thead>
          <tbody class="rate-rows"></tbody>
        </table>
        <div>
          <button class="add-rate" onclick="addRate(this)">Add Rate</button>
          <button class="remove-rate" onclick="removeRate(this)">Remove Rate</button>
        </div>
      </td>
      <td class="total-amount">रू 0.00</td>
      <td>
        <button onclick="addProductRow()">Add Product</button>
        <button onclick="removeProductRow(this)">Remove Product</button>
      </td>
    </tr>
  </tbody>
</table>

<div class="buttons">
  <button onclick="history.back()">Back to Challan CRUD</button>
  <button onclick="calculateTotal()">Calculate Total</button>
  <button onclick="saveChallan()">Save Challan</button>
  <button onclick="cancelForm()">Cancel</button>
</div>

<table>
  <tr>
    <td colspan="7" class="total-row">Grand Total:</td>
    <td id="grand-total" class="total-amount">रू 0.00</td>
  </tr>
</table>

<script src=".6.0.min.js"></script>
<script src="/[email protected]/dist/js/select2.min.js"></script>
发布评论

评论列表(0)

  1. 暂无评论