I have copied and pasted code from the firebase documentation itself, still I am getting this error:
WARN Possible Unhandled Promise Rejection (id: 0):
ReferenceError: Can't find variable: getDownloadURL
import storage from "#react-native-firebase/storage";
const pickImageAndUpload = async () => {
try {
launchImageLibrary({
quality: 0.5
}, (fileobj) => {
console.log(fileobj.assets[0].uri);
const uploadTask = storage().ref().child(`/userprofile/${Date.now()}`).putFile(String(fileobj.assets[0].uri))
uploadTask.on('state_changed',
(snapshot) => {
const progress = (snapshot.bytesTransferred / snapshot.totalBytes) * 100;
if (progress == 100) alert('image uploaded')
},
(error) => {
// Handle unsuccessful uploads
alert('error uploading image')
},
() => {
getDownloadURL(uploadTask.snapshot.ref).then((downloadURL) => {
setImage(downloadURL)
});
}
);
})
} catch (err) {
alert(err)
console.log(err);
}
}
I don't know why this error is coming, I have searched everywhere, this error does not occur in any other person code, please help me
You can check the official documentation here
If you are using React Native Firebase then getDownloadURL() is a method on StorageReference and not a function (like in Modular SDK). Try refactoring the code as shown below:
const storageRef = storage().ref().child(`/userprofile/${Date.now()}`)
const uploadTask = storageRef.putFile(String(fileobj.assets[0].uri))
uploadTask.on('state_changed', (snapshot) => {
const progress = (snapshot.bytesTransferred / snapshot.totalBytes) * 100;
if (progress == 100) alert('image uploaded')
}, (error) => {
// Handle unsuccessful uploads
alert('error uploading image')
}, () => {
storageRef.getDownloadURL().then((downloadURL) => {
setImage(downloadURL)
});
});
Related
I'm using firebase storage to upload images, here's the problem
when I upload image A it shows up as some 9bytes file in storage folder,
then I upload image B, the image A shows up in storage, it returns the link of it too.
This sequence goes on for however many images I upload.
I can't seem to figure out what's wrong?
Here's my code:
<input
type="file"
id="file"
ref={inputFile}
style={{ display: "none" }}
onChange={handleImageChange}
/>
handleImageChange():
const handleImageChange = (e) => {
if (e.target.files[0]) {
setImage(e.target.files[0]);
uploadFiles();
}}
uploadFiles finction:
const uploadFiles = () => {
const uploadTask = storage.ref(`ProfilePictures/${user.uid}.png`).put(image);
uploadTask.on(
"state_changed",
(snapshot) => {
const prog = Math.round(
(snapshot.bytesTransferred / snapshot.totalBytes) * 100
);
setProgress(prog);
},
(error) => console.log(error),
() => {
storage
.ref("ProfilePictures")
.child(`${user.uid}.png`)
.getDownloadURL()
.then((url) => {
console.log(url);
});
}
);
};
The problem here is uploadFiles gets triggered before the state changes.
That's why it is showing the previous state (image) in the Storage Folder.
Corrected Code:
const handleImageChange = (e) => {
if (e.target.files[0]) {
setImage(e.target.files[0]);
uploadFiles(e.target.files[0]);
}
};
const uploadFiles = (file) => {
const uploadTask = storage.ref(`ProfilePictures/${user.uid}.png`).put(file);
uploadTask.on(
"state_changed",
(snapshot) => {
const prog = Math.round(
(snapshot.bytesTransferred / snapshot.totalBytes) * 100
);
setProgress(prog);
},
(error) => console.log(error),
() => {
storage
.ref("ProfilePictures")
.child(`${user.uid}.png`)
.getDownloadURL()
.then((url) => {
console.log(url);
});
}
);
};
I have a composable in vue that uploads data to firebase storage. It works, but I cannot get the data out of the composable. I think it has something to do with a return or where I'm defining terms?
The code below is built around the documentation available for firebase Storage (https://firebase.google.com/docs/storage/web/upload-files).
useStorage.js
import { ref } from "vue";
import { projectStorage } from "../firebase/config";
import {
uploadBytesResumable,
getDownloadURL,
ref as storageRef,
} from "#firebase/storage";
const useStorage = () => {
const error = ref(null);
const url = ref(null);
const filePath = ref(null);
const uploadImage = async (file) => {
filePath.value = `images/${file.name}`;
const storageReference = storageRef(projectStorage,
filePath.value);
const uploadTask =
uploadBytesResumable(storageReference, file);
await uploadTask.on(
"state_changed",
(snapshot) => {
const progress =
(snapshot.bytesTransferred / snapshot.totalBytes)
* 100;
console.log("Upload is " + progress + "% done");
},
(err) => {
console.log(err);
error.value = err.message;
},
() => {
getDownloadURL(uploadTask.snapshot.ref).then((downloadURL)
=> {
console.log("File available at", downloadURL);
url.value = downloadURL;
console.log(url.value); <--HAS CORRECT VALUE
return url.value; <--DOESNT DO ANYTHING
});
}
);
console.log(url.value);
};
return { url, filePath, error, uploadImage }; <--URL IS
NOT RETURNING OUT OF THIS COMPOSABLE
};
export default useStorage;
A simpeler approach would be to await getDownloadUrl: url.value = await getDownloadURL(uploadTask.snapshot.ref). Then, you can get rid of the .then on that function. Right now, return url.value is assigned to nothing.
Warning: Also write some sort of catch - in case something would go wrong - in a production environment.
I have some code to open the camera with React Native and save the image using FireBase, but it gives me an error saying filePath expects a string value.
Here is my code:
const openCamera = ()=>{
launchCamera({quality:0.5},(fileobj) =>{
console.log(fileobj)
const uploadTask = storage().ref().child(`/items/${Date.now()}`).putFile(fileobj.uri)
uploadTask.on('state_changed',
(snapshot) => {
var progress = (snapshot.bytesTransferred / snapshot.totalBytes) * 100;
if (progress == 100){alert("Uploaded")}
},
(error) => {
alert("something went wrong")
},
() => {
uploadTask.snapshot.ref.getDownloadURL().then((downloadURL) =>{
console.log(downloadURL)
setImage(downloadURL)
});
}
);
})
}
The launchCamera method accepts a callback that will be called with a response object. This response object has four keys; didCancel, errorCode, errorMessage, and assets.
assets is an array of the selected media, so you'll need to grab the first one.
const openCamera = () => {
launchCamera({ quality: 0.5 }, (result) => {
if (result.errorCode || result.didCancel) {
return console.log('You should handle errors or user cancellation!');
}
const img = result.assets[0];
const uploadTask = storage()
.ref()
.child(`/items/${Date.now()}`)
.putFile(img.uri);
uploadTask.on(
'state_changed',
(snapshot) => {
var progress = (snapshot.bytesTransferred / snapshot.totalBytes) * 100;
if (progress == 100) {
alert('Uploaded');
}
},
(error) => {
alert('something went wrong');
},
() => {
uploadTask.snapshot.ref.getDownloadURL().then((downloadURL) => {
console.log(downloadURL);
setImage(downloadURL);
});
},
);
});
};
I saw your problem and I have a solution for you .
I don't know why but please try to use like this once :
fileobj.assets[0].uri
Here is the buttonUploadClicked function, and I have imported firebasestorage as const storage = firebase.storage; But still the error is there
This function is run when a button is clicked and error shows only when the button is clicked
Code is below
const handleUpload = () => {
var imageName = Math.random(0, 10000) * Math.random(0, 100);
if (image) {
const uploadTask = storage.ref(`images/${imageName}.jpg`).put(image);
uploadTask.on(
'state_changed',
(snapshot) => {
// progress function beta
const progressP = Math.round((snapshot.bytesTransferred / snapshot.totalBytes) * 100);
setProgress(progressP);
},
(error) => {
console.log(error);
},
() => {
storage
.ref('images')
.child(`${imageName}.jpg`)
.getDownloadURL()
.then((imageUrl) => {
db.collection('posts').add({
timestamp: firebase.firestore.FieldValue.serverTimestamp(),
caption: caption,
photoUrl: imageUrl,
username: user.email.replace('#gmail.com', '').replace('.', ''),
picUrl: user.photoURL,
});
});
},
);
}
};
Try to replace
const storage = firebase.storage;
by
const storage = firebase.storage();
The "()" should do the trick - you need no reference to "firebase.storage" itself, but to that what is "produced" by it.
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();
}
);
});
},