I'm making multiple calls on an endpoint to get the image of a blob and I need to save it in localstorage so that if it exists there, it's not necessary to make the call again.
The way I'm doing it, it's not waiting for the keys to spread the setItem array.
What is the correct way to do this?
assetNameFiltered.forEach((assetName) => {
const ASSET_IMAGE = assetImageCached?.filter(({ id }) => id === assetName)[0];
if (ASSET_IMAGE) {
//
} else {
useOperationServiceHook.getAssetImageByName(assetName).then(({ data }) => {
if (data.size > 0) {
const READER = new window.FileReader();
READER.readAsDataURL(data);
READER.onloadend = () => createAssetImageCache({ id: assetName, image: READER.result });
} else {
createAssetImageCache({ id: assetName, image: '' });
}
});
}
});
Related
i'm using next JS and dropzone to upload an image and send the images to a server. i learned that next JS uses blur hash for static images when used as 'blur' in placeholder. but when it comes to dynamic images fetched from server it needs to be passed the blurhash as well.
so is there a way that i could generate BlurHash myself when i upload images and send them to server? i don't want to use API to generate these hash codes. just pure javascript
dropzone accepted images
const dispatch = useDispatch();
const images = useSelector(selectImages);
const [files, setFiles] = useState(images == [] ? [] : images);
const {getRootProps, getInputProps} = useDropzone({
onDrop: (acceptedFiles) => {
acceptedFiles.map((file, index) => {
const reader = new FileReader();
reader.onload = async function (e) {
const options = {
maxSizeMB: 5,
maxWidthOrHeight: 1920,
useWebWorker: true,
};
const compressedFile = await imageCompression(file, options);
const tot = parseInt(acceptedFiles.length) + parseInt(files.length);
if (tot > 9) {
alert("select maximum of 9 images");
} else if (parseInt(acceptedFiles.length) > 9) {
alert("maximum images to be selected is 9");
} else if (parseInt(files.length) < 9) {
setFiles((prevState) => [
...prevState,
{
id: index,
src: URL.createObjectURL(compressedFile),
name: file.name,
},
]);
files.map((filename) => {
acceptedFiles.forEach((newFile) => {
if (newFile.name == filename.name) {
alert("a duplicate image is detected");
setFiles(
files,
files.filter((val) => val !== newFile)
);
}
});
});
} else {
alert("something went wrong");
}
};
reader.readAsDataURL(file);
return file;
});
},
})
and the output when uploaded
i'm being able to upload the files but i don't know how i can get the URL links. I have the const fileArr which will receive each file, but i don't know how i can access it.
const fileUpload = (name: string) => {
let fileArr: { name: string; url: string; type: string }[] = [];
let objectArr: any[] = [];
Object.entries(file).forEach(([key, value]) => objectArr.push(value));
if (file !== null) {
const res = new Promise((resolve, reject) => {
objectArr.forEach((item: any) => {
const fileRef = ref(storage, `${name}/${item.name}`);
uploadBytes(fileRef, item).then(() => {
getDownloadURL(fileRef).then((url) => {
fileArr.push({ name: item.name, url, type: item.type });
});
});
if (!fileArr) {
reject("error");
} else {
resolve(fileArr);
}
});
});
res
.then((value) => {
return value;
})
.catch((error) => {
console.log(error);
});
}
};
I'm calling this function like this
const letsTry = () => {
const result = fileUpload("anyname");
console.log(result);
};
The console just logs 'undefined'. How should i do this?
EDIT
So, at the 'then catch' expression, before it returns i put a console.log. It's logging 'error', but the images are getting uploaded.
res
.then((value) => {
console.log(value);
return value;
})
.catch((error) => {
console.log(error);
return "error";
});
The problem is on this line:
if (!fileArr) {
Since you initialize fileArray as let fileArr: { name: string; url: string; type: string }[] = [];, it always has a value - even if it is an empty array.
And since both uploadBytes and getDownloadURL are asynchronous operations, you resolve the promise before any upload has completed.
What you'll want to do is instead check at the end of getting a download URL whether you now have all download URLs that you expect.
You can do this with Promise.all(), but you can also simply compare the number of the original files you're uploading with the number of download URLs you have, each time you got a new download URL. That should be something like this:
objectArr.forEach((item: any) => {
const fileRef = ref(storage, `${name}/${item.name}`);
uploadBytes(fileRef, item).then(() => {
getDownloadURL(fileRef).then((url) => {
fileArr.push({ name: item.name, url, type: item.type });
if (fileArr.length === objectArr.length) {
resolve(fileArr);
}
});
});
});
The 4th line:
Object.entries(file).forEach(([key, value]) => objectArr.push(value));
I think the varible file is undefined in line 4.
I tried to download the image which is in firebase storage which link is store in database. When I tried to download the image, it takes more time to execute while for loop is completed.
Is there any process that somehow I download in time which doesn't make the function really slow? I already solve this issue using setTimeout but I hope there may be a better solution than mine. Help me! thank you!
export const shampooHandler = () => {
return (dispatch) => {
dispatch(shampooStart());
const data = [];
const imgList = [];
fire
.database()
.ref()
.child("Shampoo")
.once("value")
.then((response) => {
for (let i = 0; i < response.val().length; i++) {
fire.storage().refFromURL(response.val()[i].img).getDownloadURL().then((image) => {
imgList.push(image);
})
.catch((error) => {
dispatch(shampooError(error));
});
setTimeout(() => {
name = response.val()[i].name;
description = response.val()[i].description;
value = response.val()[i].value;
img = imgList[i];
data.push({ name, description, value, img });
if (i === (response.val().length - 1)) {
dispatch(shampooSuccess(data));
}
}, 3000);
}
})
.catch((error) => {
dispatch(shampooError(error));
});
};
};
I spend a day finding a right solution for it. It may help someone to find solution in future. Thanks guys for giving a thought and specially DougStevensen to tiggering me an idea
export const shampooHandler = () => {
return (dispatch) => {
dispatch(shampooStart());
const data = [];
const imglist = [];
fire.database().ref().child("Shampoo").once("value").then((response) => {
response.val().forEach(element => {
const promise = imageUrlHandler(element.img).then(url => {
return url;
}).catch(error =>{
dispatch(shampooError(error));
})
imglist.push(promise);
//all the promise call to download the images
Promise.all(imglist).then(items =>{
const dataCollection = {
name: element.name,
description: element.description,
value: element.value,
img: items[items.length - 1]
}
data.push(dataCollection);
if(data.length === response.val().length){
dispatch(shampooSuccess(data));
}
}).catch(err =>dispatch(shampooError(err)));
})
}).catch(error => {
dispatch(shampooError(error));
})
}
}
export const imageUrlHandler = (databaseUrl) => {
return new Promise((resolve,reject)=> {
fire.storage().refFromURL(databaseUrl).getDownloadURL().then((url) => {
resolve(url);
})
.catch((error) => {
reject(error)
});
})
}
im building this simple application using Vue/vuex and firebase where i want to facilitate users upload images and once the app gets updated those images get reached from firebase storage , modifying the current database with the new uploaded image
Here is my code:
createMeet({ commit, getters }, payload) {
const newMeet = {
title: payload.title,
description: payload.description,
location: payload.location,
date: payload.date,
video_url: payload.video_url,
idCreator: getters.getUser.id
}
let image_url;
let key;
firebase.database().ref('meetUps').push(newMeet)
.then((data) => {
console.log(data)
key = data.key
return key
})
.then(key => {
const filename = payload.image.name
const fileExtension = filename.slice(filename.lastIndexOf('.'))
return firebase.storage().ref('meetUps/' + key + '.' + fileExtension).put(payload.image)
})---the image get storaged in the firebase storage
.then(fileData => {
image_url = fileData.metadata.downloadURLs()
return firebase.database().ref('meetUps/').child(key).update({ image_url: image_url })
})--------->updating in the database the storaged object in there passing a new paranmeter
image_url, with a new value contained in variable iimage_url
.then(() => {
commit('meetsCreator', {
...newMeet,
image_url: image_url,------------>putting changes in some mutation which modifies the state
id: key,
})
})
.catch(error => {
console.log(error)
})
// commit('meetsCreator',newMeet)
},
the images get push to the firebase storaged but once i try to modify the database adding this new element (image) using downloadUrls, doesnt work.
Any advice please?....thanks in advance!!!
You need to use the getDownloadURL() method from the JavaScript SDK, which is asynchronous and returns a Promise that resolves with the download URL.
So, the following should do the trick:
//...
firebase.database().ref('meetUps').push(newMeet)
.then(ref => {
key = ref.key
const filename = payload.image.name
const fileExtension = filename.slice(filename.lastIndexOf('.'))
return firebase.storage().ref('meetUps/' + key + '.' + fileExtension).put(payload.image)
})
.then(uploadTaskSnapshot => {
return uploadTaskSnapshot.ref.getDownloadURL();
.then(url => {
return firebase.database().ref('meetUps/').child(key).update({ image_url: url })
})
//....
I'm facing yet another issue.
I'm using firebase db to store text and firebase storage to store files. And here comes my issue.
Q: How to fetch a correct image from storage when fetching particular element from database?
Here's my attempt:
const storageRef = firebase.storage().ref('companyImages/companyImage' + 123);
^^^^^^^^^^^^ I dont have access to id yet :(
const task = storageRef.put(companyImage);
task.on('state_changed', () => {
const percentage = (snap.bytesTransferred / snap.totalBytes) * 100;
// ^^^^^^^^^^^^ not sure if i even need this
}, (err) => {
console.log(err);
}, () => {
firebase.database().ref('offers').push(values);
^^^^^^^^^^^^^^^ now I could retrieve id from it with .key but its too late
});
As you can see, first what Im doing is uploading the image and when it's succesful, Im starting to upload the data to database.
Still, it doesnt work as it is supposed to. When uploading image I have to name it with a correct id to retrieve it easily later, in components.
It may look a lil bit complex but will appreciate any kind of help. Any suggestion or hint.
Should I firstly upload data to DB and then image to the storage?
You can generate the push ID before you upload the file – you can also just save the download URL of the returned snapshot at task.snapshot.downloadURL so you don't have to retrieve the file from storage using the storage ref.
const offerRef = firebase.database().ref('offers').push();
const storageRef = firebase.storage().ref(`companyImages/${offerRef.key}`);
const task = storageRef.put(companyImage);
task.on('state_changed', (snap) => {
const percentage = (snap.bytesTransferred / snap.totalBytes) * 100;
}, (error) => {
console.log(err);
}, () => {
offerRef.set(values);
});
I would suggest using .getDownloadURL(). Then push all your uploadedfileDownloadURL's into an object or array and then store that into your database. So in the future you can access this object or array from, lets say your user/ProfilePHotos, and then in your app level code you can just use the DownloadURL as a uri links inside an image tag!
In this example I am using react-native, I upload multiple photos, save the download URL each time in an array, then set the array to firebase under the users account.
export const userVehiclePhotoUploadRequest = (photos, user, year) => dispatch => {
console.log('Inside vehiclePhotoUpload Actions', photos, user)
let referenceToUploadedPhotos = [];
return new Promise((resolve, reject) => {
photos.map(ele => {
let mime = 'application/octet-stream'
let uri = ele.uri
let uploadUri = Platform.OS === 'ios' ? uri.replace('file://', '') : uri
let sessionId = new Date().getTime()
let uploadBlob = null
let imageRef = firebase.storage().ref('vehicleImages/' + `${user.account.uid}`).child(`${sessionId}`)
fs.readFile(uploadUri, 'base64')
.then((data) => {
return Blob.build(data, { type: `${mime};BASE64` })
})
.then((blob) => {
uploadBlob = blob
return imageRef.put(blob, { contentType: mime })
})
.then(() => {
uploadBlob.close()
return imageRef.getDownloadURL()
})
.then((url) => {
referenceToUploadedPhotos.push(url)
console.log('ARRAY OF URLS WHILE PUSHING', referenceToUploadedPhotos)
resolve(url)
})
.catch((error) => {
reject(error)
})
})
})
.then(() => {
//I did this to not go home until photos are done uploading.
let vehicles;
firebase.database().ref('users/' + user.account.uid + `/allVehicles/allVehiclesArray`).limitToFirst(1).once('value').then(function (snapshot) {
// ******** This method is straight from their docs ********
// ******** It returns whatever is found at the path xxxxx/users/user.uid ********
vehicles = snapshot.val();
}).then(() => {
console.log('ARRAY OF URLS BEFORE SETTING', referenceToUploadedPhotos)
// let lastVehicle = vehicles.length - 1;
firebase.database().ref('users/' + user.account.uid + `/allVehicles/allVehiclesArray/` + `${Object.keys(vehicles)[0]}` + `/photosReference`).set({
referenceToUploadedPhotos
}).then(() => {
dispatch(loginRequest(user.account))
})
})
})
};
And then in your code, lets say inside a map of the user's information...
{ ele.photosReference !== undefined ? dynamicAvatar = { uri: `${ele.photosReference.referenceToUploadedPhotos[0]}` } : undefined }