1084

How do I build a regular form with a multi-file Uploader field?

Comments for “How do I build a regular form with a multi-file Uploader field?”
 

Posted by Lethalmiko on Wednesday 5th June 2024 at 11:07 GMT

I want to build a normal form with different fields but it must have a multi-file Uploader as one of the fields. I like the JavaScript-driven one specifically for images, but I want one for any kind of file (including documents).

And after uploading the files (before I hit the Submit button on the form), there should be a way of capturing the uploaded file paths into an array (which I can pass into a database field as a JSON array) after submitting the form. The other form fields will go into other database columns.

I have not seen an obvious way to do all this in one step since the image Uploader is a separate module with no connection to the main data entry form and I have so far not see anything in the documentation or videos to show clearly how this can be done in one step in one form.

I know I can add multiple single upload fields using

echo form_file_select('attachment1');
echo form_file_select('attachment2');
echo form_file_select('attachment3');
etc,

but this is not ideal because the number of attachments is not known and may even be ten or twenty!

Help!!!
Level One Member

Lethalmiko

User Level: Level One Member

Date Joined: 26/05/2024

Posted by ak1 on Wednesday 5th June 2024 at 22:45 GMT

Hi,

I don't think I'm answering all of your questions, just giving you enough to get started.

BIG, FAT, HAIRY DISCLAIMER: The following example does NOT perform any validation whatsoever. It is for demonstration purposes ONLY and should NOT be used as is in production.

Let's say the module is called products. So, in my modules/products/controllers/Products.php controller file, I add the following methods:

function multi_file_upload(): void {
		$data['view_file'] = 'multi_file_upload';
		$this->template('public', $data);
	}

	function show_file_data(): void {
		print_r($_FILES);
		die();
	}


Then, in my modules/products/views/multi_file_upload.php view file, I have:

<?php
echo form_open('products/show_file_data', ['enctype' => 'multipart/form-data']);
echo form_file_select('attachments[]', null, 'multiple');
echo form_submit('upload', 'Upload');
echo form_close();


So when you navigate to your /products/multi_file_upload route, you'll have a form that allows you to upload multiple files. When you click Upload, the form action, /products/show_file_data, will print out the file data sent to PHP, just to give you an idea.

Some useful references:
https://www.php.net/manual/en/features.file-upload.multiple.php
https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/file#multiple
https://www.youtube.com/watch?v=K_W5ZqwEcqs

Hope this helps.

Cheers,

A.K.

This comment was edited by ak1 on Wednesday 5th June 2024 at 22:46 GMT

Level One Member

ak1

User Level: Level One Member

Date Joined: 16/01/2023

Posted by Lethalmiko on Thursday 6th June 2024 at 08:46 GMT

Thank you AK for the effort, and I am aware of that particular method of putting multiple files on one upload field. My use case however requires that the files are uploaded before I submit the form and I can see them on a list on the same form with the ability to delete any file in case (for example) I selected some wrong files. This is why I said that the picture Uploder for multiple files which uses JavaScript is perfect if it can be modified to handle any type of file and embedded within a standard form.

I have tried calling the picture upload module within my module in a template file but it gives an error which is related to the route. I suppose I could reverse engineer starting from the picture upload module but that will probably take me a lot of time as I am no JavaScript expert and I am likely to spend a whole week troubleshooting my own inevitable mistakes. Hence my coming in here as I assumed that such a thing would be obvious for the resident experts in Trongate.

In fact, I think a file upload field in the data entry / edit forms should be a standard out-of-the-box feature when building a module using the Trongate App. I also cannot create a drop down, radio or checkbox using the desktop App, so it wastes time because I first have to create a normal text input field using varchar or textarea and then edit the form in the view file to create these other form field types.
Level One Member

Lethalmiko

User Level: Level One Member

Date Joined: 26/05/2024

Posted by ak1 on Thursday 6th June 2024 at 23:55 GMT

Ah, OK. Now I see what you're after. I got confused because you say 'uploaded', but, if I'm understanding what you need correctly, the files don't actually need to be uploaded for the user to confirm their selection.

We just want to list the file names, and perhaps other metadata like file size, so that the user can confirm their selection BEFORE submitting the form and uploading the files.

I tried implementing what you described, listing each file name as a control, where the user could click 'X' or similar to prevent that file from being uploaded, but the JavaScript got pretty nasty pretty quickly, and the whole thing just felt like a high effort, low gain proposition.

So, here's a stripped down suggestion. Compared to my previous example, only the view file is different. Again, no validation is being done here, etc, etc.

<?php
echo form_open('products/show_file_data', ['enctype' => 'multipart/form-data', 'id' => 'upload-form']);
echo form_file_select('attachments[]', ['id' => 'multi-file-upload', 'onchange' => 'confirmFiles()'], 'multiple');
echo '<p id="selected-files" style="display: none;">Selected file(s):</p>';
echo '<ul id="file-list-ul" style="display: none; margin-top: 10px;"></ul>';
echo '<p id="confirm" style="display: none;">Not the file(s) you wanted? Click Browse to start over.</p>';
echo '
';
echo form_submit('upload', 'Upload', ['id' => 'upload-button']);
echo form_close();
?>

<script>
const fileListUl = document.getElementById('file-list-ul');
const multiFileUpload = document.getElementById('multi-file-upload');
const selectedFiles = document.getElementById('selected-files');
const confirm = document.getElementById('confirm');

function confirmFiles(){
	fileListUl.innerHTML = '';
	selectedFiles.style.display = 'block';
	fileListUl.style.display = 'block';
	const fileList = multiFileUpload.files;
	for (file of fileList){
		fileListUl.innerHTML += `<li>${file.name}</li>`;
	}
	confirm.style.display = 'block';
}
</script>


NOTE: Replace echo ''; with echoing an HTML br tag. There's some formatting issue with the Help Bar that won't display that particular tag correctly in the code example

So in this example, the user can't manually remove each file individually, but they are displayed a list of each file name they are about to upload. If the preview is not what they want, they can click 'Browse' on the multi-file input to start over.

Hopefully this gets you a little closer to what you're trying to achieve.

This comment was edited by ak1 on Friday 7th June 2024 at 00:03 GMT

Level One Member

ak1

User Level: Level One Member

Date Joined: 16/01/2023

Posted by Lethalmiko on Saturday 8th June 2024 at 06:40 GMT

Thanks AK. I shall test out the code and give feedback.

I used the term "Uploaded" because that is exactly what happens with the multi-picture Uploader. When you select photos, they get uploaded automatically without having to click a submit button and they are immediately listed with the option to delete using a small X that appears on each one.

So I had imagined that the entire multi-file upload thing can be embedded within a form that has other fields instead of it being a standalone module. But the challenge was that after that process is done, there has to be a way to capture the file paths of the uploaded files as an array to be submitted together with the rest of the form fields into a database. I suppose the file paths array can be fed into some hidden variable using JS and it is used in the form submission.

I actually experimented with using a normal upload field with the "multiple" tag and got it to work perfectly but I had to write my own method to process multiple files because the "upload" method in the "File" class for handling uploads in Trongate is deficient. It only accepts one file and cannot handle arrays of files. Even the validation method cannot handle an array of files so I will have to write a foreach statement and put the results of each validation into an array and then check to see if any file fails the validation.

I was actually a little surprised that handling multiple files does not come straight out of the box. Is there somewhere to suggest such new features?
Level One Member

Lethalmiko

User Level: Level One Member

Date Joined: 26/05/2024

Posted by Lethalmiko on Tuesday 16th July 2024 at 13:09 GMT

AK,

Apologies for taking long to respond. I got tied up with projects.

I eventually decided to go with a normal file upload but I had to write my own class (extending the File class) to process multiple files submitted in an array and I also added some code to delete all the files when the database record is deleted. So my issue is resolved by default.
Level One Member

Lethalmiko

User Level: Level One Member

Date Joined: 26/05/2024

×