When uploading files, there needs to be a way to identify which files belong to which record. One approach could be to store each uploaded file in a database table. This table would include the filename, the file path (if needed), and the associated record ID.
With this structure, the relevant files can then be displayed using an embedded iFrame.
What do you think?
Re: configure Uppy
Posted: Wed Jul 02, 2025 7:09 pm
by johan
Kev1n
Sounds good. Do you have an example?
Johan
Re: configure Uppy
Posted: Wed Jul 02, 2025 7:16 pm
by kev1n
The first step is to create a new table with a primary key, along with fields for the file name, record ID, and possibly the form ID. This setup is particularly useful if multiple forms use the upload feature, as it allows you to clearly identify which file belongs to which form and record.
Next, you’ll need to update the upload procedure so that after a successful upload, the file information is inserted into the new table.
One important detail to consider is that a new record doesn't have a record ID yet, which complicates things.
The simplest solution is to only allow file uploads for records that have already been saved. There are ways to handle uploads for unsaved records as well, but I would recommend starting with the simpler approach. I can try to create an example later today.
Re: configure Uppy
Posted: Wed Jul 02, 2025 7:20 pm
by johan
Thanks a lot dit your help.
Re: configure Uppy
Posted: Wed Jul 02, 2025 10:14 pm
by kev1n
Follow these steps to set up file uploads with nuBuilder and Uppy.
If anything is unclear or you need more details, just let me know!
Index
Create the Files Upload Table
Create a PHP Procedure
Update the Uppy Object
Create a Run/iFrame Object
Refresh the iFrame
Screenshot 2025-07-03 043348.png
(Expand to view)
1. Create the Files Upload Table
In phpMyAdmin (or your preferred database tool), run the following SQL to create a table for storing uploaded file metadata:
Create a PHP function (for example, named nu_upload_file_sample) that validates the upload, moves the file, and records its details in the database. Adjust $targetDirectory if you want to store files elsewhere.
uppy.setMeta({
procedure: 'nu_upload_file_sample', // <-- upload procedure to use
session_id: window.nuSESSION,
record_id: nuRecordId() // <-- pass record id
})
4. Create a Run/iFrame Object
Create a Run/Iframe Object in your form to display the uploaded files. E.g. width object ID iframe_files
Set filter: #RECORD_ID# to display only the files that belong to that record.
Also include the record ID in the browse columns (hidden)
Add this JS to Custom Code/Browse to handle file downloads:
4. Create a Run/iFrame Object
• Add a Run/IFrame Object (e.g., with the ID iframe_files) to your form to display uploaded files.
• Set its filter to #RECORD_ID# so it only shows files for the current record.
• Include the record ID as a (hidden) browse column.
run_files.png
run_browse_columns.png
5. Refresh the iFrame
To automatically refresh the file list after each upload, add this function to your form’s Custom Code:
function nuSelectBrowse(event, element) {
const selectedFileName = nuBrowseRow(element, 1).value; // file name in the second column
downloadFile(selectedFileName);
}
Re: configure Uppy
Posted: Thu Jul 03, 2025 12:17 pm
by johan
Kev1n
I've switched the columns and now it works.
Thanks for your help.
Johan
Re: configure Uppy
Posted: Thu Jul 03, 2025 1:20 pm
by kev1n
Regarding the error message: I encountered the same issue initially when my upload directory didn’t exist yet. It seems like the error handling isn’t quite working correctly, and there may be other cases where an error could occur as well.
I’ll take a closer look at it when I get the chance.
If you discover anything in the meantime, please let me know.
Re: configure Uppy
Posted: Thu Jul 03, 2025 1:55 pm
by johan
Kev1n
I asked gemini to solve the error.
This is it's solution and it works.
<div id="#uppy_div#"></div>
<script>
// Voer de initialisatiefunctie uit zodra het DOM geladen is
$(document).ready(function() {
nuInitUppy();
});
function nuInitUppy() {
// Gebruik const voor variabelen die niet opnieuw worden toegewezen
const $objId = $('#' + '#this_object_id#');
const targetDivId = '#uppy_div#'; // Bewaar de ID zonder '#' prefix, als je die later nodig hebt
// Declareer uppyResponseMessage in de scope van nuInitUppy
// Dit zorgt ervoor dat het toegankelijk is voor alle nested functies en callbacks.
let uppyResponseMessage = '';
// Initialiseer Uppy
const uppy = nuUppyCreate(); // Aanname: nuUppyCreate() retourneert een Uppy-instantie
uppy.use(Uppy.Dashboard, {
inline: true,
bundle: true,
// Zorg ervoor dat nuCSSNumber betrouwbare getallen retourneert, anders kan dit problemen geven.
// Optioneel: Voeg fallback-waarden toe als $objId.nuCSSNumber() null of undefined kan zijn.
height: $objId.nuCSSNumber('height') || 400, // Voorbeeld fallback
width: $objId.nuCSSNumber('width') || '100%', // Voorbeeld fallback
target: '#' + targetDivId, // Zorg voor de '#' prefix voor de selector
showProgressDetails: true,
replaceTargetContent: true,
method: 'post'
})
.use(Uppy.XHRUpload, {
endpoint: 'core/nuapi.php',
shouldRetry: (xhr) => { return false; }, // Geen retries bij falen
// onAfterResponse is voor het inspecteren van de *initiële* serverrespons,
// vaak gebruikt voor het verwerken van headers of niet-standaard responsen.
// Het is beter om de algemene status en berichten af te handelen in 'complete'.
async onAfterResponse(xhr, response) {
// Parsen van de JSON-respons is hier nuttig voor specifieke HTTP-statussen
// of als de server een niet-standaard 'message' veld gebruikt.
try {
const jsonData = JSON.parse(xhr.responseText);
// Je kunt hier de uppyResponseMessage instellen op basis van een fout,
// maar de 'complete' handler is vaak robuuster.
if (xhr.status === 401) {
uppyResponseMessage = jsonData.message || 'Authenticatie mislukt.';
throw new Error(uppyResponseMessage); // Gooi een error om Uppy te laten weten dat er een probleem is
}
// Optioneel: Als de server een algemeen bericht stuurt bij succes
// if (xhr.status >= 200 && xhr.status < 300 && jsonData.message) {
// uppyResponseMessage = jsonData.message;
// }
} catch (e) {
// Fout bij parsen of andere XHR-gerelateerde fouten
uppyResponseMessage = 'Fout bij verwerken van server respons.';
// Je kunt hier besluiten om de error door te gooien of niet, afhankelijk van Uppy's gedrag.
// console.error("Error parsing XHR response:", e);
// throw e; // Gooi de error door als dit een kritieke fout is voor Uppy
}
}
});
// Deze callback wordt uitgevoerd voordat de upload begint.
// Dit is de juiste plaats om meta-data in te stellen voor de upload.
uppy.on('upload', (data) => { // 'data' object bevat de bestanden die worden geüpload
uppy.setMeta({
procedure: 'nu_upload_file_sample', // Server-side procedure om te gebruiken
session_id: window.nuSESSION,
record_id: nuRecordId() // Record ID waaraan de upload gekoppeld moet worden
});
});
// Deze callback wordt geactiveerd wanneer *alle* uploads (succesvol of mislukt) zijn voltooid.
uppy.on('complete', (result) => {
// Reset het bericht voor elke nieuwe upload-sessie
uppyResponseMessage = '';
if (result.successful.length > 0) {
// Als er succesvolle uploads zijn, pak het bericht van de eerste succesvolle upload.
// Dit veronderstelt dat je PHP-script een 'message' veld retourneert bij succes.
uppyResponseMessage = result.successful[0].response.body.message || 'Bestand(en) succesvol geüpload.';
} else if (result.failed.length > 0) {
// Als er mislukte uploads zijn, pak de foutmelding.
// Hier proberen we de foutmelding uit de serverrespons te halen,
// anders vallen we terug op Uppy's eigen foutbericht.
const firstFailed = result.failed[0];
uppyResponseMessage = firstFailed.response && firstFailed.response.body && firstFailed.response.body.message
? firstFailed.response.body.message
: firstFailed.error.message || 'Fout bij het uploaden van bestand(en).';
} else {
// Geen bestanden geselecteerd of geüpload
uppyResponseMessage = 'Geen bestanden verwerkt.';
}
// Roep de custom handler functie aan met het uiteindelijke bericht
if (window.nuOnFileUploadComplete) {
nuOnFileUploadComplete('FS', $objId.attr('id'), result, uppyResponseMessage);
}
});
// Optioneel: Voeg een algemene foutafhandeling toe voor Uppy.
// Dit vangt fouten op die niet direct in onAfterResponse worden afgehandeld.
uppy.on('error', (error) => {
console.error('Uppy error:', error);
// Je kunt uppyResponseMessage hier ook instellen als een generieke foutboodschap.
// uppyResponseMessage = error.message || 'Er is een algemene uploadfout opgetreden.';
});
}
</script>