Fix file input bug
August 29, 2025 · AI Conversations
const cards = document.querySelectorAll(".uploadtrigger");
const fileInputs = document.querySelectorAll(".inputFileHidden");
if (cards && fileInputs) {
cards.forEach(card => {
card.addEventListener("click", function () {
const target = this.getAttribute("data-target");
const fileInput = document.getElementById(target);
fileInput.click();
});
});
}
// when file selected, start upload with progress
document.querySelectorAll(".inputFileHidden").forEach(input => {
input.addEventListener("change", function (e) {
const file = this.files?.[0];
const securityID = document.querySelector('input[name="SecurityID"]').value;
if (!file) return;
const inputId = this.id;
let objectID = 0;
if(document.getElementById('ObjectIDModal')){
objectID = document.getElementById('ObjectIDModal').value;
}
const uiWrap = document.querySelector(`.upload-ui[data-for="${inputId}"]`);
const progress = uiWrap?.querySelector('.progress');
const bar = uiWrap?.querySelector('.progress-bar');
const preview = uiWrap?.querySelector('.upload-preview');
const label = document.querySelector(`.uploadtrigger[data-target="${inputId}"] .file-name`);
const endpoint = document.querySelector(`.uploadtrigger[data-target="${inputId}"]`)?.getAttribute('data-action');
const fieldName = document.querySelector(`.uploadtrigger[data-target="${inputId}"]`)?.getAttribute('data-field') || this.name;
const hiddenId = uiWrap?.querySelector('.upload-image-id');
const table = document.querySelector(`.uploadtrigger[data-target="${inputId}"]`)?.getAttribute('data-table');
if (!endpoint) {
console.warn('No data-endpoint on uploadtrigger for', inputId);
return;
}
// show chosen filename
if (label) label.textContent = file.name;
// show basic preview immediately
if (file.type.startsWith('image/')) {
if (preview) {
const reader = new FileReader();
reader.onload = ev => {
preview.src = ev.target.result;
preview.style.display = 'block';
};
reader.readAsDataURL(file);
}
}else{
}
// show UI
if (uiWrap) uiWrap.style.display = 'block';
if (bar) { bar.style.width = '0%'; bar.textContent = '0%'; }
// build request
const formData = new FormData();
formData.append(fieldName, file); // e.g. "Bilder" or "Image"
formData.append('field',fieldName);
if (securityID) formData.append('SecurityID', securityID);
if (table) formData.append('table', table);
if (objectID!=0) formData.append('objectID', objectID);
const xhr = new XMLHttpRequest();
xhr.open('POST', endpoint, true);
xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
// progress
xhr.upload.onprogress = function (ev) {
if (ev.lengthComputable && bar) {
const pct = Math.round((ev.loaded / ev.total) * 100);
bar.style.width = pct + '%';
bar.textContent = pct + '%';
}
};
xhr.onload = function () {
try {
const res = JSON.parse(xhr.responseText || '{}');
if (xhr.status >= 200 && xhr.status < 300 && res.ok) {
// use canonical URL from server (published asset)
if(file.type.startsWith('image/')){
if (res.url && preview) preview.src = res.url;
}else{
alert("dsdsa");
if (res.url && preview) preview.href = res.url;
preview.textContent = 'View';
preview.style.display = 'block';
preview.target = '_blank';
}
file.value = '';
// if (res.id && hiddenId) hiddenId.value = res.id; // store ImageID for later submit
} else {
alert(res.message || 'Upload failed');
}
} catch (e) {
alert('Upload failed');
}
};
xhr.onerror = function () {
alert('Network error during upload');
};
xhr.send(formData);
});
});
});
jQuery(document).ready(function($) {
$('.dashboardwrapper').on('click', '.delete-btn', function(e) {
e.preventDefault();
if (!confirm("Datei wirklich löschen?")) return;
var btn = jQuery(this);
var field = btn.data('field');
var fileslot = btn.closest('.file-slot');
var objectID = btn.data('objectid');
var action = btn.data('action');
var table = btn.data('table');
var securityID = jQuery('input[name="SecurityID"]').val();
jQuery.ajax({
url: action + '?objectId=' + objectID,
method: 'POST',
data: {
field: field,
objectId: objectID,
table: table,
SecurityID: securityID
},
success: function(res) {
if (res.ok) {
alert("Datei gelöscht: " + field);
// update UI: remove preview, disable button
fileslot.fadeOut();
} else {
alert(res.error || "Fehler beim Löschen");
}
},
error: function(xhr) {
alert("Serverfehler: " + xhr.status);
}
});
});
});
when again click file option after uploaded earlier then upload not start without refresh page
1) Clear the input **before** opening the picker, so choosing the same file triggers `change`.
2) Keep a reference to the input element and clear it **after** upload (success or failure).
3) Optional: reset the progress UI each time.
Here are the exact changes to make:
document.addEventListener("DOMContentLoaded", function () {
const cards = document.querySelectorAll(".uploadtrigger");
if (cards) {
cards.forEach(card => {
card.addEventListener("click", function () {
const target = this.getAttribute("data-target");
const fileInput = document.getElementById(target);
if (!fileInput) return;
// ✅ important: clear the input so picking the same file fires "change"
fileInput.value = "";
fileInput.click();
});
});
}
// when file selected, start upload with progress
document.querySelectorAll(".inputFileHidden").forEach(input => {
input.addEventListener("change", function () {
const inputEl = this; // ✅ keep a ref to the input element
const file = inputEl.files?.[0];
const securityID = document.querySelector('input[name="SecurityID"]')?.value || "";
if (!file) return;
const inputId = inputEl.id;
let objectID = 0;
const objectIDEl = document.getElementById('ObjectIDModal');
if (objectIDEl) objectID = objectIDEl.value;
const uiWrap = document.querySelector(`.upload-ui[data-for="${inputId}"]`);
const progress = uiWrap?.querySelector('.progress');
const bar = uiWrap?.querySelector('.progress-bar');
const preview = uiWrap?.querySelector('.upload-preview');
const trigger = document.querySelector(`.uploadtrigger[data-target="${inputId}"]`);
const label = trigger?.querySelector('.file-name');
const endpoint = trigger?.getAttribute('data-action');
const fieldName = trigger?.getAttribute('data-field') || inputEl.name;
const hiddenId = uiWrap?.querySelector('.upload-image-id');
const table = trigger?.getAttribute('data-table');
if (!endpoint) {
console.warn('No data-action on uploadtrigger for', inputId);
return;
}
// filename
if (label) label.textContent = file.name;
// basic preview for images (instant)
if (file.type.startsWith('image/') && preview && 'src' in preview) {
const reader = new FileReader();
reader.onload = ev => {
preview.src = ev.target.result;
preview.style.display = 'block';
};
reader.readAsDataURL(file);
}
// show/reset UI
if (uiWrap) uiWrap.style.display = 'block';
if (bar) { bar.style.width = '0%'; bar.textContent = '0%'; }
// build request
const formData = new FormData();
formData.append(fieldName, file);
formData.append('field', fieldName);
if (securityID) formData.append('SecurityID', securityID);
if (table) formData.append('table', table);
if (objectID) formData.append('objectID', objectID);
const xhr = new XMLHttpRequest();
xhr.open('POST', endpoint, true);
xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
// progress
xhr.upload.onprogress = function (ev) {
if (ev.lengthComputable && bar) {
const pct = Math.round((ev.loaded / ev.total) * 100);
bar.style.width = pct + '%';
bar.textContent = pct + '%';
}
};
xhr.onload = function () {
// ✅ always clear input so user can re-select the same file again
inputEl.value = "";
try {
const res = JSON.parse(xhr.responseText || '{}');
if (xhr.status >= 200 && xhr.status < 300 && res.ok) {
// Update preview using final canonical URL from server
if (res.url && preview) {
if (file.type.startsWith('image/') && 'src' in preview) {
preview.src = res.url;
preview.style.display = 'block';
} else {
// support non-image: treat preview as a link if it's an <a>
if ('href' in preview) {
preview.href = res.url;
preview.textContent = preview.textContent?.trim() || 'View';
preview.target = '_blank';
preview.style.display = 'inline-block';
}
}
}
// if (res.id && hiddenId) hiddenId.value = res.id;
} else {
alert(res.message || 'Upload failed');
}
} catch (e) {
alert('Upload failed');
}
};
xhr.onerror = function () {
// ✅ also clear on error so user can retry with same file
inputEl.value = "";
alert('Network error during upload');
};
xhr.send(formData);
});
});
});
// jQuery delete stays the same
jQuery(document).ready(function($) {
$('.dashboardwrapper').on('click', '.delete-btn', function(e) {
e.preventDefault();
if (!confirm("Datei wirklich löschen?")) return;
var btn = $(this);
var field = btn.data('field');
var fileslot = btn.closest('.file-slot');
var objectID = btn.data('objectid');
var action = btn.data('action');
var table = btn.data('table');
var securityID = $('input[name="SecurityID"]').val();
$.ajax({
url: action + '?objectId=' + objectID,
method: 'POST',
data: {
field: field,
objectId: objectID,
table: table,
SecurityID: securityID
},
success: function(res) {
if (res.ok) {
alert("Datei gelöscht: " + field);
fileslot.fadeOut();
} else {
alert(res.error || "Fehler beim Löschen");
}
},
error: function(xhr) {
alert("Serverfehler: " + xhr.status);
}
});
});
});
### Why this fixes it
– `fileInput.value = ""` before `.click()` ensures selecting the **same** file fires `change`.
– `inputEl.value = ""` after upload (success/error) resets the input for the next attempt.
– Previously you had `file.value=''` which does nothing (that `file` is a `File`, not the input). This was preventing re-uploads without a page refresh.
If you also want to reset the preview/progress on every new selection (so the UI is clean before upload starts), add this right after you compute `uiWrap/bar/preview`:
if (bar) { bar.style.width = '0%'; bar.textContent = '0%'; }
if (preview) {
if (file.type.startsWith('image/') && 'src' in preview) {
preview.removeAttribute('src');
} else if ('href' in preview) {
preview.removeAttribute('href');
preview.textContent = '';
}
preview.style.display = 'none';
}
Just replace this line:
fileslot.fadeOut();
with this:
fileslot.find('.upload-preview').hide(); // hide preview images/links
fileslot.find('.progress').hide(); // hide progress bar if needed
fileslot.find('.file-name').text(''); // clear file name label
or if you literally want to hide *everything inside* `.file-slot`:
fileslot.children().hide();
That way the parent `.file-slot` stays in the DOM (not removed), but all its inner elements (image, link, bar, labels) get hidden.
✅ Example updated snippet:
success: function(res) {
if (res.ok) {
alert("Datei gelöscht: " + field);
// instead of removing the whole slot, clear its children
fileslot.children().hide();
} else {
alert(res.error || "Fehler beim Löschen");
}
}
Do you want the slot’s UI to be **reset to initial state** (like “Choose file” text + hidden preview), or literally just hide everything inside?