Instance.publish (list of files)

If anyone has 2 mins, could I ask for an example of how to publish an array of files into a list of files state within the plugin builder? I can’t seem to get it right today!

function(instance, properties, context) {
    
    const fileArray = [];
    
 // open file dialog
    var input = document.createElement('input');
    input.type = 'file';
    input.multiple = 'multiple';
    input.onchange = e => {
        
     // add files to state
        for (var i=0; i < e.target.files.length; i++) {
            
            fileArray.push(e.target.files[i]);
            
        }
        
        console.log(fileArray);
        
     // trying to poopulate the list of files state with the array of files which is in fileArray
     // do we have to populate it with base64 data or something?
        
        instance.publishState("files_selected", fileArray);
        
    };
    
    input.click();
    
}

The state called “files_selected” is a list of files but I can’t just publish the file array to it without running into the error of “UnexpectedError Expected a file url as a string, but got a object”.

Have tried a number of things, do we have to read each file in fileReader, get base64 and do it that way?

Anyone who may have an example, I would be appreciate since there doesn’t seem to much about this on the forum :frowning:

Regards

I am not in front of my computer but I think you have to first use the context.uploadContent function on each of the files within your for loop and then pass that array of objects which is returned from it, to your instance.publishState

Oh ok, thanks for the reply.
So context.uploadContent is used to upload file(s) to the Bubble storage, I hadn’t thought about them having to be uploaded first before putting them into a state. I shall try that, thank you.

1 Like

Yeah. The files will be uploaded to the server. The server returns a URL. Your state would be populated with a list of URLs

Is there a way without uploading files into bubble storage?

Although I’m not a technical Bubblespert, I don’t believe so. Perhaps others may chime in here.

I’m wondering if you need to use the base64 data, latest version is looking like this but I still can’t see anything in the states file list.

function(instance, properties, context) {

 // get data
    var max_file_size = properties.max_file_size ? properties.max_file_size : '';
    const fileArray = [];
    
 // get base64
    function getBase64(file) {
        var reader = new FileReader();
        reader.readAsDataURL(file);
        reader.onloadend = function () {
            var base64String = reader.result;
            var base64Substring = base64String.substr(base64String.indexOf(',') + 1);
            fileArray.push(base64Substring);
        };
        reader.onerror = function (err) {
            console.log("Error: " + err);
        };
    }
    
 // open file dialog
    var input = document.createElement('input');
    input.type = 'file';
    input.multiple = 'multiple';
    input.onchange = e => {
        
     // check each file size when max file size has been set
        if (max_file_size) {
            for (var i=0; i < e.target.files.length; i++) {
                if (Math.round(e.target.files[i].size / 1000) > max_file_size) {
                    instance.publishState("mux_upload_error", "One or more files selected is too large, max file size allowed is " + max_file_size + "kb");
                    instance.triggerEvent('mux_upload_error');
                    return;
                }
            }
        }
        
     // add files to state
        for (var i=0; i < e.target.files.length; i++) {
            
            getBase64(e.target.files[i]);
            // fileArray.push(e.target.files[i]);
            
        }
        console.log(fileArray);
        instance.publishState("files_selected", fileArray);
        
    };
    
    input.click();
    
}

I was hoping to create an action which simply opens a file popup dialog client side, allows for some files to be selected and put those files straight into a file list, with a purpose of then using that list as an input for a server side action. I wasn’t too sure if there was a way to run a server action which opens up a client popup file dialog.

What I want to avoid is uploading them in bubble storage because if a file is like 5gb (or more) in size, it will make this action rather slooow.

I know eventually I’ll figure this thing out!

Ok, so let’s take it step by step.
Indeed you will not upload it to Bubble, so keep not using Bubble’s file upload API.

Also, the “file” data type, as was mentioned, is a URL. If you “console.log” a file type, it will be something like this "//aws.s3.com/appforest/bubbleappname/wewewew.pdf" which is a link!

So you will not deal with URLs since no upload will happen and consequently also not deal with “file” data type.

The option then is to make it text type and pass to your server side action the base64 version of the file, which is just a text after all. Make it a list because that’s what you want, so pass an array of texts.

Genius! thanks @vini_brito
Just one problem with it, browser crashes with large files since it’s all being held in memory.
Would you think it’s possible to get the blob URL (rather than the base64) held in a state like this?
I can easily read in a 5GB blob file, maybe more but since I’ve learned base64 is typically 33% larger in file size I think this is gonna cause a few issues later down the line.
I’m going to see if I can get the blobs stored as URL’s in a text list anyway.

Not to be accessible to the server side. If you want to handle files larger than the memory available in the computer, then you can stream it or use a specific storage that allows for that, I think it’s persistent storage, google around it and see if it helps you!

My plugin does exactly this … If anyone would like to reference the code to see how I do it, check it out here:

It’s open source!