In the introduction to firebase's real-time database tutorial I explained how we can use firebase to store, retrieve and edit data in a non-sql real-time database.
Storage is another service that firebase provides. Using this service we are able to upload and use files to google's cloud. Basically, we are able to upload our webpage assets and use them as if they were hosted in our own server.
Setting up our files
The last tutorial covered how to set up a fire base project. If you haven't read that, you definitely should. Then, you can simply continue with this tutorial.
Wellcome back :)
So, we have two files, the HTML an JavaScript file. The HTML is going to have a file input button, that's how we will upload files.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Firebase Storage</title>
<script type="text/javascript" src="https://www.gstatic.com/firebasejs/4.8.0/firebase.js"></script>
</head>
<body>
<div id="uploading">
<progress value="0" max="100" id="progressBar">0%</progress>
<label for="submit">Click to upload</label>
<input type="file" value="upload" id="submitButton" />
</div>
<script type="text/javascript" src="script.js"></script>
</body>
</html>
As covered in the last tutorial, we have the filebase library at the top, our script file at the bottom. An input field to upload the file, where as the lable and progress are simply for decore!
I'll leave the css up to you but to illustrate what we are doing, this is what I have (with the help of css)
We'll need to use the initial Firebase configuration code, as we did in the last tutorial, everything apart from the sections concerning the database. Add the following to the script.js
:
var config = {
apiKey: "*******************",
authDomain: "******.firebaseapp.com",
databaseURL: "https://******.firebaseio.com",
projectId: "******",
storageBucket: "******.appspot.com",
messagingSenderId: "***************"
};
firebase.initializeApp(config);
Setting up storage restrictions
Just as we've done with the database, in order to play around with storage we need to remove the restrictions so that we can read and write without needing authentication. It's clearly a bad idea to do this in production but this is just to give us the freedom to learn this service in isolation.
All you need to do is navigate to Storage
then rules
and then edit read and write privileges to true
Working with storage()
If you navigate to Storage
, then files
you'll see the message, "there are no files here yet". Our aim in this tutorial is to add files in there from our web app/site.
Let's do that.
In script.js
let's initialise the Storage()
service.
const storage = firebase.storage()
There's a two step process to uploading a file to the storage. Firstly we need to specify where we want the file to go and what name it should have.
let locationRef = storage.ref('cats/cat1.jpg')
Above we are saying call the file cat1.jpg
and add it into a folder cold cats
.
So far that's just a reference, it does nothing, it simply waits for the file to be put
into it. The following line actually pushes the local file to the firebase server.
locationRef.put([the file])
Uploading files to firebase storage
As you saw, there are only three lines of code to get an asset stored in the firebase storage. Now let's use those in combination with vanilla JavaScript to make actual uploads.
In our HTML we had this code
<label for="submit">Click to upload</label>
<input type="file" value="upload" id="submitButton" />
A user clicks on the input/label, then is required to select an asset and finally we want to upload that asset to firebase
const storage = firebase.storage()
const submitButton = document.getElementById('submitButton');
submitButton.addEventListener('change', (e)=>{
let file = e.target.files[0];
let locationRef = storage.ref('cats/' + file.name)
locationRef.put(file)
})
As you can see, the exact same lines. This time the name of the file will be the same name of the local file, and the file being pushed to the server is the file itself.
If you go back to the firebase console, to Storage
, you'll see your cats folder and inside it, your cat photos!
Getting feedback from the process
As usuall when considering user experience we need to be able to provide information through out the process. For example it be cool to know:
- How long the upload is taking?
- did it actually upload successfully?
- What is the new location address?
Similar to the database()
service, storage()
also has an on()
method which observes state_changed
observer, within which we are able to observe the uploading process, catch any errors, and be aware when the upload is complete.
submitButton.addEventListener('change', (e)=>{
let file = e.target.files[0];
let locationRef = storage.ref('cats/' + file.name)
let task = locationRef.put(file)
task.on('state_changed',
function progress(snapshot){
// whilst uploading
},
function error(error){
//error handling
},
function complete(){
// on completion
}
)
})
Note how we attached locationRef.put(file)
to a variable, now we are able to observe it's state throughout the process:
task.on('state_changed',
function progress(snapshot){ //progress
let per = (snapshot.bytesTransferred / snapshot.totalBytes) *100;
uploader.value = per;
},
function error(error){ },
function complete(){
console.log('Done')
}
)
The first function watches the process, and as you can see, it gives us the total number of bytes of the original file, and the number of bytes that have been uploaded. We are using those numbers to get a percentage and we are adding that to the progress. Incase it's confusing uploader
refers to the progress
element:
<progress value="0" max="100" id="progressBar">0%</progress>
let uploader = document.getElementById('progressBar')
Reading files from storage
In order to get a file out of storage, you need to know the folder it's in and its file name. With that the full url can be found.
let storageRef = storage.ref('cats')
let image = storageRef.child('cat1.png');
The above can be writen in one line as we'll see later on:
let storageRef = storage.ref('cats/cat.png');
To get the actual url and display it on the page:
image.getMetadata().then(function(metadata) {
document.getElementById('img').src = metadata.downloadURLs[0]
}).catch(function(error) { /*error handling*/ });
Assuming we had an image tag with the id of img
, the cat from storage would be sat on the browser :)
Deleting files
Deleting is just as simple as everything else, follows the same pattern: point to the file, then run delete()
on it
let storageRef = storage.ref('cats/cat.png');
storageRef.delete().then(function() {
// removed
}).catch(function(error) {
// not removed :(
});
Combining storage with the database
I should end the tutorial here but just because the main reason I can think of that google gave storage with firebase is so that it can be used with the database, I am going to combine the two right now!
Let's revisit the event listener from above:
submitButton.addEventListener('change', (e)=>{
let file = e.target.files[0];
let locationRef = storage.ref('cats/' + file.name)
let task = locationRef.put(file)
task.on('state_changed',
...
function complete(){
// on completion
}
)
})
When the uploading is complete we want to store the full url to the database.
You can easily do this yourself by following the last tutorial
const database = firebase.database()
const ref = database.ref('cats');
submitButton.addEventListener('change', (e)=>{
...
task.on('state_changed',
...
function complete(){
storageRef.getMetadata().then(metadata=>{
ref.push({
url: metadata.downloadURLs[0]
})
})
}
)
})
Exactly the same as in the last tutorial, in lines 1-2 we define the database service and where the content should go. Inside complete
function (which doesn't have to have a name, as you know) we push to the database. Now if you check the database, you'll see a cats
node and a child node with the cat url. Note that metadata
gives more information, such as the time when the file was uploaded and so you can get more information to store in the database.
Conclusion
This was fun. Stay tuned for few more tutorials on firebase. I have authentication to cover, and production mode (covering how we can protect the configuration settings), then anything else that I might think of conserning firebase services.
Top comments (1)
Can you provide a sample webpage with this in implementation for clear idea?