i wanna save my uploaded images in a folder called "course-cover" in firebase storage
this is my code that saves uploaded images in the route of storage directly but instead of thet i wanna save them in the "course-cover" folder
async function storeCoverCourse(coverCourse) {
return new Promise((resolve, reject) => {
const storage = getStorage();
const filename = `${coverCourse.name}-${uuidv4()}`;
const storageRef = ref(storage, filename);
const uploadTask = uploadBytesResumable(storageRef, coverCourse);
uploadTask.on(
"state_changed",
(snapshot) => {
// Observe state change events such as progress, pause, and resume
// Get task progress, including the number of bytes uploaded and the total number of bytes to be uploaded
const progress =
(snapshot.bytesTransferred / snapshot.totalBytes) * 100;
console.log("Upload is " + progress + "% done");
switch (snapshot.state) {
case "paused":
console.log("Upload is paused");
break;
case "running":
console.log("Upload is running");
break;
}
},
(error) => {
// Handle unsuccessful uploads
reject(error);
},
() => {
// Handle successful uploads on complete
// For instance, get the download URL: https://firebasestorage.googleapis.com/...
getDownloadURL(uploadTask.snapshot.ref).then((downloadURL) => {
resolve(downloadURL);
});
}
);
});
}
const imgUrls = await Promise.all(
[...cover].map((coverCourse) => storeCoverCourse(coverCourse))
).catch((error) => {
toast.error("image not uploaded");
return;
});
const formDataCopy = {
...formData,
imgUrls,
timestamp: serverTimestamp(),
};
delete formDataCopy.cover;
await addDoc(collection(db, "courses"), formDataCopy);
The storageRef is a StorageReference and you essentially specify path of your file with it. If your path contains /, that'll be like a directory. Try:
const filename = `course-cover/${coverCourse.name}-${uuidv4()}`;
const storageRef = ref(storage, filename);
It's not actually a folder under the hood but just a namespace. For more details, see How to create a folder in Firebase Storage?
In addition to the solution that #Dharmaraj covered in their answer, you should also get rid of the problematic use of the Promise constructor with Promise returning functions. It can be eliminated because the uploadTask object is a thenable/promise-like object.
async function storeCoverCourse(coverCourse) {
const storage = getStorage();
const filename = `course-cover/${coverCourse.name}-${uuidv4()}`;
const storageRef = ref(storage, filename);
const uploadTask = uploadBytesResumable(storageRef, coverCourse);
uploadTask.on(
"state_changed",
(snapshot) => {
// Observe state change events such as progress, pause, and resume
// Get task progress, including the number of bytes uploaded and the total number of bytes to be uploaded
const progress =
(snapshot.bytesTransferred / snapshot.totalBytes) * 100;
console.log("Upload is " + progress + "% done");
switch (snapshot.state) {
case "paused":
console.log("Upload is paused");
break;
case "running":
console.log("Upload is running");
break;
}
}
);
return uploadTask
.then(snapshot => snapshot.ref.getDownloadURL());
}
Related
I use Firebase Storage with React. I have an array with multiple images. For every single image in it I do an upload to Firebase. Once I get the downloadUrl back, I want to store it in a hook array for further use. However, my array is always empty. Why ?
If I use the useEffect hook as soon as the array changes, I get an output every time the downloadUrl is inserted into the array. However: One line per URL and not an array with the URLs
const [uploadBilder, setUploadBilder] = useState([]);
await Promise.all(
mehrBilder?.map((bild) => {
const storageRef = ref(
storage,
`${aktuellerUser._id}/artikelBilder/` + bild.name
);
const uploadTask = uploadBytesResumable(storageRef, bild);
uploadTask.on(
"state_changed",
(snapshot) => {
const progress =
(snapshot.bytesTransferred / snapshot.totalBytes) * 100;
console.log("Upload is " + progress + "% done");
switch (snapshot.state) {
case "paused":
console.log("Upload is paused");
break;
case "running":
console.log("Upload is running");
break;
}
},
(error) => {
console.log(error);
},
() => {
getDownloadURL(uploadTask.snapshot.ref).then((downloadURL) => {
setUploadBilder((prev) => [...prev, downloadURL]);
console.log(uploadBilder); //EMPTY
});
}
);
})
);
useEffect(() => {
console.log(uploadBilder) //count 3 = right!
},[uploadBilder]}
As I work on an Instagram clone using React and Firebase, it doesn't seem to be uploading images to my Firebase database.
In my image upload component, I have a progress bar, a caption, and an image upload button. In the first instance, it uploads a null or empty image and in the second instance, it uploads the image that I selected at the beginning or first instance.
Here is my image component
const date = new Date().getTime();
let storageRef = ref(storage, `post/${date}.png`);
const upload = (e) => {
e.preventDefault();
if (postimg && postcaption) {
const uploadTask = uploadBytesResumable(storageRef, postimg);
uploadTask.on(
"state_changed",
(snapshot) => {
const progress =
(snapshot.bytesTransferred / snapshot.totalBytes) * 100;
console.log("Upload is " + progress + "% done");
setprogress(progress);
},
(error) => {
// Handle unsuccessful uploads
},
() => {
postUpload();
}
);
} else {
console.log("all feild are mendatory ");
}
};
const postUpload = async () => {
let url = await getDownloadURL(storageRef);
setPosturl(url);
console.log(Posturl);
console.log("i am api link " + Posturl);
let post = await addDoc(posts, {
caption: postcaption,
avatar: profileImg,
post: Posturl,
username: "username",
});
setpostcaption("");
setprogress(0);
alert("i am upload ");
};
Firebase database doesn't show anything being uploaded to the "posts" collection and the second instance the image url at post that I selected at first instance isn't being uploaded.
I am not sure if that is an issue with my ImageUpload or Firebase.
I cant preview the image inside the store, it says undefined I manage to upload it on images/ folder but the name of the file is undefined instead of the actual name of the image
const uploadFile = () => {
console.log(selectedImages);
const storageRef = ref(storage, 'images/' + selectedImages.name);
const uploadTask = uploadBytesResumable(storageRef, selectedImages, metadata);
console.log(selectedImages);
uploadTask.on('state_changed',
(snapshot) => {
const progress = (snapshot.bytesTransferred / snapshot.totalBytes) * 100;
console.log(progress);
console.log('Upload is ' + progress + '% done');
switch (snapshot.state) {
case 'paused':
console.log('Upload is paused');
break;
case 'running':
console.log('Upload is running');
break;
default:
break;
}
},
(error) => {
console.log(error);
},
() => {
// Upload completed successfully, now we can get the download URL
getDownloadURL(uploadTask.snapshot.ref).then((downloadURL) => {
console.log('File available at', downloadURL);
});
}
);
};
import {uploadString} from "#firebase/storage";//use this in rather than uploadbytes
uploadString(imageRef,imageToPost,'data_url')//use format of your file type it works for me
I'm useing Firestore in my Vue project and I'm working on a feature that allows users to upload images, however I'm facing the following issue:
I have a 'newMarker' placeholder object that the user fills in with information and once the user confirms the input, the object is saved to the database. When the user confirms the input I want to:
Save the image in Firebase Storage
Get the generated URL for that file
Add the URL to the newMarker object
and then push the newMarker object with the included imgURL to the database
However I can't figure out how to make the code wait for the callback function that runs as soon as the upload status is completed (in the uploadIMG function, 'uploadTask.on(firebase.storage.TaskEvent.STATE_CHANGED', last callback function) and returns a promise with the url. No matter what I do, this callback function is executed last.
When the user confirms the input, saveNewMarker() is executed and the following code will run:
My code:
async saveNewMarker() {
await this.uploadImg();
console.log('Image upload finished! Pushing new marker to db')
await db.collection(this.user.email).add({
position: this.newMarker.position,
type: this.newMarker.type,
location: this.newMarker.location,
imgURL: this.newMarker.imgURL
})
.then((marker) => {
console.log('marker added to database')
this.newMarker.id = marker.id
})
},
async uploadImg(){
console.log('Uploading image ...')
const storageRef = firebase.storage().ref();
const uploadTask = storageRef.child('user-uploads/images/' + this.file.name).put(this.name)
uploadTask.on(firebase.storage.TaskEvent.STATE_CHANGED,
(snapshot) => {
const progress = (snapshot.bytesTransferred / snapshot.totalBytes) * 100;
console.log('Upload is ' + progress + '% done');
},
(error) => {
console.log(error)
},
async () => {
const imgURL = await uploadTask.snapshot.ref.getDownloadURL()
console.log('uploaded image: ' + imgURL)
this.newMarker.imgURL = imgURL
}
);
},
Output:
Uploading image ...
Upload is NaN% done
Image upload finished! Pushing new marker to db
marker added to database
uploaded image: https://firebasestorage.googleapis.com/v0/b/....
Expected output:
Uploading image ...
Upload is NaN% done
uploaded image: https://firebasestorage.googleapis.com/v0/b/....
Image upload finished! Pushing new marker to db
marker added to database
That's not how async/awaits are intended to be used, I would recommend using Promises instead, like this:
function saveNewMarker() {
// Call uploadImg as a Promise and wait for the result
this.uploadImg()
.then((imgURL) => {
console.log('Image upload finished! Pushing new marker to db');
db.collection(this.user.email).add({
position: this.newMarker.position,
type: this.newMarker.type,
location: this.newMarker.location,
imgURL: this.newMarker.imgURL
})
.then((marker) => {
console.log('marker added to database');
this.newMarker.id = marker.id;
})
}).catch((error) => {
//Do something
});
};
function uploadImg() {
// Return a promise that will either resolve or emit an error
return new Promise((resolve, reject) => {
console.log('Uploading image ...');
const storageRef = firebase.storage().ref();
const uploadTask = storageRef.child('user-uploads/images/' + this.file.name).put(this.name);
uploadTask.on(firebase.storage.TaskEvent.STATE_CHANGED,
(snapshot) => {
const progress = (snapshot.bytesTransferred / snapshot.totalBytes) * 100;
console.log('Upload is ' + progress + '% done');
},
(error) => {
console.log(error);
// An error occurred so inform the caller
reject(error);
},
async () => {
const imgURL = await uploadTask.snapshot.ref.getDownloadURL();
console.log('uploaded image: ' + imgURL);
this.newMarker.imgURL = imgURL;
// We 'awaited' the imgURL, now resolve this Promise
resolve(imgURL);
}
);
});
};
And remember your semicolons to avoid unintended behavior or errors.
You will have to wrap code within uploadImg in promise and resolve it once image upload is done. Refactoring uploadImg to something like below should work:
async uploadImg() {
return new Promise((resolve, reject) => {
console.log("Uploading image ...");
const storageRef = firebase.storage().ref();
const uploadTask = storageRef.child("user-uploads/images/" + this.file.name).put(this.name);
uploadTask.on(
firebase.storage.TaskEvent.STATE_CHANGED,
(snapshot) => {
const progress = (snapshot.bytesTransferred / snapshot.totalBytes) * 100;
console.log("Upload is " + progress + "% done");
},
(error) => {
console.log(error);
reject(error);
},
async () => {
const imgURL = await uploadTask.snapshot.ref.getDownloadURL();
console.log("uploaded image: " + imgURL);
this.newMarker.imgURL = imgURL;
resolve();
}
);
});
},
async UPLOAD_IMAGES() {
try {
let self = this;
var storageRef = firebase.storage().ref();
var files = document.getElementById("photoupload").files;
var file = files[0];
// Create the file metadata
var metadata = {
contentType: "image/jpeg"
};
// Upload file and metadata to the object 'images/mountains.jpg'
var uploadTask = storageRef
.child(`${this.name}/` + file.name)
.put(file, metadata);
// Listen for state changes, errors, and completion of the upload.
uploadTask.on(
firebase.storage.TaskEvent.STATE_CHANGED, // or 'state_changed'
function(snapshot) {
// Get task progress, including the number of bytes uploaded and the total number of bytes to be uploaded
var progress =
(snapshot.bytesTransferred / snapshot.totalBytes) * 100;
console.log("Upload is " + progress + "% done");
switch (snapshot.state) {
case firebase.storage.TaskState.PAUSED: // or 'paused'
console.log("Upload is paused");
break;
case firebase.storage.TaskState.RUNNING: // or 'running'
console.log("Upload is running");
break;
}
},
function(error) {
// A full list of error codes is available at
// https://firebase.google.com/docs/storage/web/handle-errors
switch (error.code) {
case "storage/unauthorized":
// User doesn't have permission to access the object
break;
case "storage/canceled":
// User canceled the upload
break;
case "storage/unknown":
// Unknown error occurred, inspect error.serverResponse
break;
}
},
function() {
// Upload completed successfully, now we can get the download URL
uploadTask.snapshot.ref
.getDownloadURL()
.then(function(downloadURL) {
console.log("File available at", downloadURL);
self = downloadURL;
});
}
);
} catch (error) {
console.log("ERR ===", error);
alert("Image uploading failed!");
}
}
this is my full function for the image upload. Only issue I have is it has callback functions inside this function.
function() {
// Upload completed successfully, now we can get the download URL
uploadTask.snapshot.ref
.getDownloadURL()
.then(function(downloadURL) {
console.log("File available at", downloadURL);
self = downloadURL;
});
}
Only for this part can I get async await function?
You can very well call then() on an UploadTask, as explained here: https://firebase.google.com/docs/reference/js/firebase.storage.UploadTask#then
This object behaves like a Promise, and resolves with its snapshot
data when the upload completes.
So you could do something like:
async UPLOAD_IMAGES() {
try {
let self = this;
const storageRef = firebase.storage().ref();
const files = document.getElementById("photoupload").files;
const file = files[0];
// Create the file metadata
const metadata = {
contentType: "image/jpeg"
};
const fileRef = storageRef
.child(`${this.name}/` + file.name);
const uploadTaskSnapshot = await fileRef.put(file, metadata);
const downloadURL = await uploadTaskSnapshot.ref.getDownloadURL();
self = downloadURL;
} catch (error) {
console.log("ERR ===", error);
alert("Image uploading failed!");
}
}
In case anyone needs to both observe upload progress while using await/async instead of callbacks, this code works:
try {
await saveToFirebase();
alert("Happy days!");
} catch (error) {
alert("Sad days!");
}
async function saveToFirebase() {
// Create promise.
let promise = $.Deferred();
// Set storage reference.
let storageRef = firebase.storage().ref();
// Se file path.
let filepath = "your-path.txt";
// Set content type.
let metadata = {
contentType: "text/plain",
cacheControl: "no-cache, max-age=0"
};
// Start upload.
let uploadTask = storageRef.child(filepath).putString(data, "raw", metadata);
// Monitor state of upload operation.
uploadTask.on(firebase.storage.TaskEvent.STATE_CHANGED, function(snapshot) {
// Get task progress, including number of bytes uploaded and total number of bytes to be uploaded.
let progress = (snapshot.bytesTransferred / snapshot.totalBytes);
// Display progress to user.
// Error during upload?
}, function(error) {
promise.reject(error);
// Nope, upload succeeded.
}, function() {
promise.resolve();
});
// Return promise.
return promise;
}