I'm kinda still new to web development and just started working on a POS system as a fun little project. I'm struggling really hard with my items page, I basically need all crud to be done on one page and I tried using AJAX to accomplish this, so far I have a button you click, and it shows the modal that has a form to add a new item, and it works but seems to execute twice, so I get two of the same item, but it only shows the extra one when I manually refresh the page. Everything I've seen points to how my javascript is loaded, but any help with be appreciated.
Here's my javascript:
document.addEventListener('turbolinks:load', () => {
// Function to open the "New Item" modal
newItemButton.addEventListener('click', () => {
newItemModal.style.display = 'block';
});
// Function to open the "Edit Item" modal
editItemButtons.forEach(button => {
button.addEventListener('click', () => {
const itemId = button.dataset.id;
const formData = new FormData(editItemForm);
// Use AJAX to fetch item details and populate the form
fetch(`/items/${itemId}/update_item`, {
method: 'PATCH', // Use PATCH method for updates
headers: {
'X-CSRF-Token': csrfToken,
'Accept': 'application/json'
},
body: formData
})
.then(response => {
if (!response.ok) {
throw new Error('Network response was not ok');
}
return response.json();
})
.then(item => {
const form = editItemModal.querySelector('form');
form.action = `/items/${itemId}`;
form.querySelector('[name="item[name]"]').value = item.name;
form.querySelector('[name="item[cost_price]"]').value = item.cost_price;
form.querySelector('[name="item[sale_price]"]').value = item.sale_price;
form.querySelector('[name="item[category]"]').value = item.category;
editItemModal.style.display = 'block';
});
});
});
// Function to close the modals when clicking outside of them
window.addEventListener('click', event => {
if (event.target === newItemModal || event.target === editItemModal) {
newItemModal.style.display = 'none';
editItemModal.style.display = 'none';
}
});
closeButtons.forEach(button => {
button.addEventListener('click', () => {
newItemModal.style.display = 'none';
editItemModal.style.display = 'none';
});
});
newItemForm.addEventListener('submit', event => {
event.preventDefault();
const formData = new FormData(newItemForm);
fetch('/items', {
method: 'POST',
headers: {
'X-CSRF-Token': '<%= form_authenticity_token %>',
'Accept': 'application/json'
},
body: formData
})
.then(response => response.json())
.then(item => {
// Append the new item to the list without reloading the page
console.log("adding new item")
const newRow = itemList.insertRow();
newRow.innerHTML = `
<td>${item.name}</td>
<td>${item.price}</td>
<td>${item.category}</td>
<td>
<button class="edit-item-button" data-id="${item.id}">Edit</button>
<button class="delete-item-button" data-id="${item.id}">Delete</button>
</td>
`;
// Reset the form and close the modal
newItemModal.style.display = 'none';
})
.catch(error => console.error('Error:', error));
});
});
class ItemsController < ApplicationController
def index
@items = current_user.items # Fetch items for the current user
end
def create
puts 'Create Item action called'
@item = current_user.items.new(item_params)
respond_to do |format|
if @item.save
puts 'item saved'
format.html { redirect_to items_path, notice: 'Item was successfully created.' }
format.json { render json: @item, status: :created }
else
puts @item.errors.full_messages
format.html { render :new }
format.json { render json: @item.errors, status: :unprocessable_entity }
end
end
end
private
def item_params
params.require(:item).permit(:name, :cost_price, :sale_price, :category)
end
end