Website File Uploads with only javascript using Firebase
Setting up a basic file upload feature for your static website with just Javascript using Firebase. No PHP needed!
I was recently building a prototype for a very basic website: Javascript, HTML, and CSS. No framework, no backend languages, very few libraries. But the site needed the ability to allow users to upload images and store them somewhere. Normally, the process might be to set up a database, communicate with a backend language of choice, set up security and authentication, etc., but that’s a lot of work for a simple proof of concept. I just wanted the most plug-and-play solution, that still allowed me to style everything the way I want, and keep control of my codebase without using someone else’s domain or someone else’s forms or someone else’s user flow. I polled my office, and everyone recommended Firebase, from Google, so that’s what I went with. And here’s the steps I took to set everything up Sign up for Firebase, and set up your first project using the add project button.
Once you’ve created the app and given it a name and region, you’ll be taken to the homepage for your project. Since we’re making a web app, click the “add firebase to your web app” button:
You’ll get a popup with a codeblock that you can very simply copy and paste into your html code. Hit the copy button, go to your HTML file, and paste it in to your page, just before the closing body tag (and before any of your custom javascript files, if you already have any set up). This snippet has everything you’ll need to authenticate with your database. No PHP / Node.js / Python needed.
By default, Firebase allows uploads only if you are logged in and authenticated. To allow uploads from anyone (not recommended, but good to test your initial configuration), we’ll have to adjust some settings in the firebase console. Go to storage > rules inside the develop menu.
There should be something in there by default:
service firebase.storage {
match /b/{bucket}/o {
match /{allPaths=**} {
allow read, write: if request.auth != null;
}
}
}
We can remove the if statement, so that it reads:
service firebase.storage {
match /b/{bucket}/o {
match /{allPaths=**} {
allow read, write;
}
}
}
NOTE:This is fine for internal testing, but when you decide to put this online, you should have some sort of restrictions on who can upload files to your database.
Now we need to add a file upload field and a submit button in our page. Something like this works well enough for illustration purposes:
<div id="filesubmit">
<input type="file" class="file-select" accept="image/*"/>
<button class="file-submit">SUBMIT</button>
</div>
Add that to your html file wherever you want the form to appear. Notice that the input field in this example allows any image as an upload type via the accept parameter.
We need to add a couple things below the initializeApp statement in the code they gave you to paste:
const storageService = firebase.storage();
const storageRef = storageService.ref();
This creates two variables: storageService is a reference to firebase storage service — it allows you to use all of the methods they make available for storing data and files.
The second, storageRef is a reference to your actual instantiation of that service — it will lead you to your specific database and root file location where things get uploaded.
Now let’s set up some handlers to make sure things happen when people use your form:
document.querySelector('.file-select).addEventListener('change', handleFileUploadChange);
document.querySelector('.file-submit).addEventListener('click', handleFileUploadSubmit);
The handleFileUploadChange function gets triggered any time someone selects a new file via the upload via the Choose File upload button. So let’s add that function:
let selectedFile;
handleFileUploadChange(e) {
selectedFile = e.target.files[0];
}
Here we create a variable called selectedFile that will keep track of whatever file a user has input via the Choose File button.
Now we need to be able to manage the submission:
handleFileUploadSubmit(e) {
const uploadTask = storageRef.child(`images/${selectedFile.name}`).put(selectedFile); //create a child directory called images, and place the file inside this directory
uploadTask.on('state_changed', (snapshot) => {
// Observe state change events such as progress, pause, and resume
}, (error) => {
// Handle unsuccessful uploads
console.log(error);
}, () => {
// Do something once upload is complete
console.log('success');
});
}
Here, we’re creating an uploadTask — this creates a child of our root storage directory called images where all our user’s uploads will go (so that we can still create other subdirectories for other kinds of uploads if we want without everything becoming a cluttered mess). Then we’re telling the task to put the file into that directory.
I’m adding a few more listeners here as placeholders, in case you want to do things like monitor progress of the upload on('state_changed') , handle errors in the upload (error)=>{}, and then the final function allows you to do something once an upload is successful. I’ll leave that up to you, and for now, we’ll just log a success message to the console.
And that’s it! You’ll need to be running a local server on your computer to test this. To do this on a mac:
- Open terminal, and type cd in the command prompt (without hitting enter)
- Open finder, and go to the root folder containing your project’s html, and drag it into the terminal window next to the cd you just typed, then hit return.
- Type python `-m SimpleHTTPServer 8000`
- Open a web browser and enter the URL: http://localhost:8000. You should see your form page containing the file upload field and submit button, and those buttons should allow you to select a file for upload, and submit it to your Firebase project database. We can check the debug console to make sure we see a success message:
Now, in the Firebase console, you should see your file as well, by going to `Develop > Storage > Files` Tab and clicking on the `images/` subdirectory.
That’s it. Some suggested next steps would be:
- Hide the submit button until the first change event fires, so that we can make sure we have a file that we can upload first before allowing submission.. Add actual error handling and success messaging so the user knows what’s happening.
- Store the image metadata as well
- Make sure users are authenticated before uploading
- Make sure files can only be uploaded from specific domains:
Good luck in your project! Hopefully this allows you to get up and running quickly with a cloud database in your static javascript app.