issues creating img dynamically - javascript

I do not understand what's going on when it comes to creating an img dynamically. This is the code:
const pics = document.querySelector('.gridPics');
eventosListener();
function eventosListener() {
document.addEventListener('DOMContentLoaded', () => {
jsonFile();
});
}
I get the pics from a json file. It works well.
function jsonFile () {
fetch('js/fotos.json')
.then(response => {
if (!response.ok) {
throw new Error(response.status);
}
return response.json();
})
.then(data => {
showPics(data);
})
.catch(function () {
this.dataError = true;
})
}
Function that must create pictures dinamically
function showPics(x) {
x.forEach(element => {
const div = document.createElement('div');
div.classList.add('grid-item');
const imagen = document.createElement('img');
imagen.setAttribute("src", element.name);
imagen.setAttribute("alt", element.desc);
imagen.setAttribute("width", '90%');
div.appendChild(imagen);
pics.appendChild(div);
});
}
HTML file
<section class="fotos">
<div class="gridPics"></div>
</section>
For a while I believed that imgs paths were wrong, but I added a img like this but it does no work either
imagen.src = 'https://i.picsum.photos/id/861/200/300.jpg?hmac=kssNLkcAZTJQKpPCSrGodykV8A6CStZxL7dHvtsVUD0';
Json File
[{
"name" : "./../assets/1.jpeg",
"desc": "imagen1"
},...
}]
The estructure
enter image description here
I do not have any error in the console but I can not see anything.

I suspect your issue is that the data is not coming in as JSON as you're loading it from a plain text file, you can solve this by ensuring they are using JSON.parse.
The below works (ignoring me having to mock out loading the data) just adding showPics(JSON.parse(data));
const jsonData = "[{\"desc\":\"imagen1\",\"name\":\"https://i.picsum.photos/id/861/200/300.jpg?hmac=kssNLkcAZTJQKpPCSrGodykV8A6CStZxL7dHvtsVUD0\" }]";
const fetch = () => Promise.resolve({ok:true, json:() => Promise.resolve( jsonData)});
const pics = document.querySelector('.gridPics');
eventosListener();
function eventosListener() {
document.addEventListener('DOMContentLoaded', () => {
jsonFile();
});
}
function jsonFile () {
fetch('js/fotos.json')
.then(response => {
if (!response.ok) {
throw new Error(response.status);
}
return response.json();
})
.then(data => {
showPics(JSON.parse(data));
})
.catch(function () {
this.dataError = true;
})
}
function showPics(x) {
x.forEach(element => {
const div = document.createElement('div');
div.classList.add('grid-item');
const imagen = document.createElement('img');
imagen.setAttribute("src", element.name);
imagen.setAttribute("alt", element.desc);
imagen.setAttribute("width", '90%');
div.appendChild(imagen);
pics.appendChild(div);
});
}
<section class="fotos">
<div class="gridPics"></div>
</section>

Related

CKEditor 5 React custom image upload adapter

I am trying to implement custom upload adapter but it is not working.
On uploading image my upload function is not running(upload function is created inside uploadAdapter function) and no request is getting sent to backend. Please see what is the problem in code.
const API_URl = "https://noteyard-backend.herokuapp.com";
const UPLOAD_ENDPOINT = "api/blogs/uploadImg";
function uploadAdapter(loader) {
return {
upload: () => {
return new Promise((resolve, reject) => {
const body = new FormData();
loader.file.then(file => {
body.append("uploadImg", file);
//AuthorizedApi is simple axios request.
AuthorizedApi.post(`${API_URl}/${UPLOAD_ENDPOINT}`, {
body,
})
.then(res => res.json())
.then(res => {
resolve({ default: `${API_URl}/${res.url}` });
})
.catch(err => {
reject(err);
});
});
});
},
};
}
function uploadPlugin(editor) {
editor.plugins._plugins.get("FileRepository").createUploadAdapter = loader => {
return uploadAdapter(loader);
};
}
//This is my CKEditor code snippet
<CKEditor
editor={TextEditor}
config={{
...EDITOR_CONFIG[theme],
extraPlugins: [uploadPlugin],
link: {
defaultProtocol: "https://",
},
}}
data={stripTrackingImage(value) ?? ""}
onReady={editor => {
//add toolbar
window.editor = editor;
if (disabled) {
editor.isReadOnly = true;
} else {
document
.querySelector(`#${toolbarId}`)
?.appendChild(editor.ui.view.toolbar.element);
editor.on("handle_attachment_click", addAttachment);
//adjust tooltip position
editor.ui.view.toolbar.items.map(item => {
//button positionging( without dropdowns)
item.tooltipPosition = "se";
//for dropdowns
if (item.buttonView) {
item.buttonView.tooltipPosition = "se";
}
return item;
});
}
console.log(editor, "editor");
}}
onChange={(event, editor) => setValue(editor.getData())}
isReadOnly={disabled}
/>
On uploading image , no request is getting sent to given URL, please try to find the problem

I can't upload image files from .vue to my database

I'm using Vue with Laravel and I tried to do a simple crud which is working good regarding things like title or description of an article (text-fields) but when I try to send an image file, it doesn't work. I have tried formData but to no avail.
This is my form in template, title goes in the database with no problem, if I console log selectedFile then it shows the file selected correctly but the addArticle method not attaching the images
<form #submit.prevent="addArticle" class="container">
<label>Title</label>
<input type="text" v-model="article.title" />
<label>Image</label>
<input type="file" v-on:change="selectedFile" />
<button type="submit">Create</button>
</form>
This is my script
<script>
export default {
data() {
return {
fileSelected: null,
article: {},
};
},
methods: {
addArticle() {
var formData =new FormData();
formData.append(this.article.image, this.fileSelected);
axios
.post("http://localhost:8000/api/articles", this.article)
.then((response) => this.$router.push({ name: "ArticlesList" }))
.catch((err) => console.log(err))
.finally(() => (this.loading = false));
}
,
selectedFile(event) {
this.fileSelected = event.target.files[0];
},
},
};
</script>
this is my code
<input type="file" #change="onFileChange">
onFileChange(e) {
this.sendphoto = e.target.files[0];
},
editUser() {
var self = this;
let formData = new FormData();
formData.append("image" , self.sendphoto )
let config = {
header : {
'Content-Type' : 'multipart/form-data'
}
}
axios.post('/edit-user' , formData , config)
.then(function (response) {
})
.catch(function (error) {
console.log(error);
})
},
You are creating a FormData object but you are not sending it within your Axios request.
In order to send the file and form data, you have to append everything to FormData object.
<script>
export default {
data() {
return {
fileSelected: null,
article: {},
};
},
methods: {
addArticle() {
var formData =new FormData();
formData.append('image', this.fileSelected);
formData.append('title', this.article.title);
axios
.post("http://localhost:8000/api/articles", formData)
.then((response) => this.$router.push({ name: "ArticlesList" }))
.catch((err) => console.log(err))
.finally(() => (this.loading = false));
}
,
selectedFile(event) {
this.fileSelected = event.target.files[0];
},
},
};
</script>
this worked in sending image files as string on database, hopefully it helps other people that are having similar problems
setup() {
const base64 = ref()
const changeFile= async(event) => {
const file = event.target.files[0];
base64.value = await convertBase64(file);
}
const convertBase64 = (file) => {
return new Promise ((resolve, reject) => {
const fileReader = new FileReader();
fileReader.readAsDataURL(file);
fileReader.onload = () => {
resolve(fileReader.result)
}
fileReader.onerror = (error) => {
reject(error)
}
})
}
const form = reactive({
title: " ",
body: " ",
image: base64,
})
const submitForm = () => {
axios.post("http://localhost:8000/api/articles", form)
}
return { changeFile, submitForm, form}
},

How to get image filename from Firebase Storage?

I am using the following:
const [allImages, setImages] = useState([]);
const getFromFirebase = () => {
//1.
let storageRef = storage.ref(user1);
//2.
storageRef.listAll().then(function (res) {
//3.
res.items.forEach((imageRef) => {
console.log(imageRef);
imageRef.getDownloadURL().then((url) => {
//4.
setImages((allImages) => [...allImages, url]);
});
});
})
.catch(function (error) {
console.log(error);
});
console.log(allImages);
};
and then displaying via:
<button onClick={getFromFirebase}>Show</button><br/><br/>
<div id="photos">
{allImages.map((image) => {
return (
<div key={image} className="image">
<img className="uploadedfile" src={image} alt="" />
<button className="buttondelete" onClick={() => deleteFromFirebase(image)}>
Delete
</button>
</div>
I realise this is returning the getDownloadURL for the image URL, but how do I also return the image filename?
To get the filename you can use getMetadata:
imageRef.getMetadata().then(metadata => {
// do something with metadata.name
});
You can use the 'getMetaData' method.
import { getStorage, ref, getMetadata } from "firebase/storage";
// Create a reference to the file whose metadata we want to retrieve
const storage = getStorage();
const forestRef = ref(storage, 'images/forest.jpg');
// Get metadata properties
getMetadata(forestRef)
.then((metadata) => {
// Metadata now contains the metadata for 'images/forest.jpg'
})
.catch((error) => {
// Uh-oh, an error occurred!
});
You can refer Firebase Docs - File Metadata for a better understanding
To get the file name and url or download link of the videos or files from the firebase storage you can use these two functions in react and javascript
// function to fetch videos/files from firebase storage
const fetchVideos = async () => {
const storageRef = firebase.storage().ref("storage folder name");
const videos = [];
await storageRef
.listAll()
.then(async function (result) {
result.items.forEach(async function (videoRef) {
// getting the name of the file
const videoName = videoRef.name;
//getting the url of the file -> calling another function for this
const videoUrl = await getVideoUrl(videoRef);
// creating the object with name and url
const videoObj = {
videoName,
videoUrl,
};
console.log("video obj", videoObj);
videos.push(videoObj);
});
})
.catch(function (error) {
// Handle any errors
return [];
});
}
// function to get download url
const getVideoUrl = (imageRef) => {
const videoLink = imageRef
.getDownloadURL()
.then(function (videoUrl) {
// console.log("videoUrl", videoUrl);
return videoUrl;
})
.catch(function (error) {
// Handle any errors
return "";
});
return videoLink;
};

Sending list of images as response using Javascript

I am making an API that gets a list of image names, then it has to download them one by one from S3 bucket and then send them all as a response.
The issue is that my images are being uploaded but it seems that when I put them in a list as base64 and then try to send the list then the list just comes up empty.
const getImagesById = async (req, res) => {
const { id } = req.params;
const imagesSet = new Map();
try {
const documentFromDB = await document.findOne({ id });
documentFromDB.devices.forEach((device) => {
const images = new Set();
device.images.forEach(item => images.add(downloadFromS3(item)))
imagesSet.set(device.name, JSON.stringify(mapToObj(images))) // tried adding just images also but neither works
});
res.status(200).json(JSON.stringify(mapToObj(imagesSet)));
} catch (e) {
console.log(`An error occurred : ${e.message}`);
res.status(500)
.send(e.message);
}
};
function mapToObj(inputMap) {
let obj = {};
inputMap.forEach(function(value, key){
obj[key] = value
});
return obj;
}
And this is how I get images from S3:
const downloadFromS3 = async (imageName) => {
try {
const image = await S3Utils.downloadFile(BUCKET_NAME, imageName);
if (image.stack) {
return null;
}
const imageBase64 = image.Body.toString('base64');
return imageBase64;
} catch (e) {
console.log(`An error occurred while downloading : ${e.message}`);
throw e;
}
};
This is the response I am getting at the moment:
"{\"{ name: 'Martin'}\":\"{\\\"[object Promise]\\\":{}}\"}"
What I am trying to do is get a lits of device names, map them in a Map as key with value as the base64 list of images and then send it all in a response to the UI to show the images with the names.
What am I doing wrong here?
You just need to add await before call the downloadFromS3 function, consequently changing all the above functions.
const getImagesById = async (req, res) => {
const { id } = req.params;
const imagesSet = new Map();
try {
const documentFromDB = await document.findOne({ id });
await Promise.all(documentFromDB.devices.map(async (device) => {
const images = new Set();
await Promise.all(device.images.map(async item => images.add(await downloadFromS3(item))))
imagesSet.set(device.name, JSON.stringify(mapToObj(images))) // tried adding just images also but neither works
}));
res.status(200).json(JSON.stringify(mapToObj(imagesSet)));
} catch (e) {
console.log(`An error occurred : ${e.message}`);
res.status(500)
.send(e.message);
}
};
function mapToObj(inputMap) {
let obj = {};
inputMap.forEach(function(value, key){
obj[key] = value
});
return obj;
}

Angular 2 Synchronous File Upload

I am trying to upload a file to web api which takes the file as byte array using angular 2 application.
I am not able to pass the byte array from angular 2 page to web api. It looks like the File Reader read method is asynchronous. How do I make this as synchronous call or wait for the file content to be loaded before executing the next line of code?
Below is my code
//attachment on browse - when the browse button is clicked
//It only assign the file to a local variable (attachment)
fileChange = (event) => {
var files = event.target.files;
if (files.length > 0) {
this.attachment = files[0];
}
}
//when the submit button is clicked
onSubmit = () => {
//Read the content of the file and store it in local variable (fileData)
let fr = new FileReader();
let data = new Blob([this.attachment]);
fr.readAsArrayBuffer(data);
fr.onloadend = () => {
this.fileData = fr.result; //Note : This always "undefined"
};
//build the attachment object which will be sent to Web API
let attachment: Attachment = {
AttachmentId: '0',
FileName: this.form.controls["attachmentName"].value,
FileData: this.fileData
}
//build the purchase order object
let order: UpdatePurchaseOrder = {
SendEmail: true,
PurchaseOrderNumber: this.form.controls["purchaseOrderNumber"].value,
Attachment: attachment
}
//call the web api and pass the purchaseorder object
this.updatePoService
.updatePurchaseOrder(this.form.controls["purchaseOrderRequestId"].value, order)
.subscribe(data => {
if (data) {
this.saveSuccess = true;
}
else {
this.saveSuccess = false;
}
},
error => this.errors = error,
() => this.res = 'Completed'
);
}
Any hint would be useful.
regards,
-Alan-
You cannot make this async call synchronous. But you can take advantage of the observables to wait for the files to be read:
//when the submit button is clicked
onSubmit = () => {
let file = Observable.create((observer) => {
let fr = new FileReader();
let data = new Blob([this.attachment]);
fr.readAsArrayBuffer(data);
fr.onloadend = () => {
observer.next(fr.result);
observer.complete()
};
fr.onerror = (err) => {
observer.error(err)
}
fr.onabort = () => {
observer.error("aborted")
}
});
file.map((fileData) => {
//build the attachment object which will be sent to Web API
let attachment: Attachment = {
AttachmentId: '0',
FileName: this.form.controls["attachmentName"].value,
FileData: fileData
}
//build the purchase order object
let order: UpdatePurchaseOrder = {
SendEmail: true,
PurchaseOrderNumber: this.form.controls["purchaseOrderNumber"].value,
Attachment: attachment
}
return order;
})
.switchMap(order => this.updatePoService.updatePurchaseOrder(this.form.controls["purchaseOrderRequestId"].value, order))
.subscribe(data => {
if (data) {
this.saveSuccess = true;
} else {
this.saveSuccess = false;
}
},
error => this.errors = error,
() => this.res = 'Completed'
);
}
I arrived here looking for a solution for a similar issue. I'm performing requests to an endpoint which can response a binary blob if anything goes well or a JSON file in event of error.
this.httpClient.post(urlService, bodyRequest,
{responseType: 'blob', headers: headers})
.pipe(map((response: Response) => response),
catchError((err: Error | HttpErrorResponse) => {
if (err instanceof HttpErrorResponse) {
// here, err.error is a BLOB containing a JSON String with the error message
} else {
return throwError(ErrorDataService.overLoadError(err, message));
}
}));
As FileReaderSync apparently doesn't work in Angular6 I took n00dl3's solution (above) to throw the error after parsing the Blob content:
return this.httpClient.post(urlService, bodyRequest,
{responseType: 'blob', headers: headers})
.pipe(map((response: Response) => response),
catchError((err: Error | HttpErrorResponse) => {
const message = `In TtsService.getTts(${locale},${outputFormat}). ${err.message}`;
if (err instanceof HttpErrorResponse) {
const $errBlobReader: Observable<HttpErrorResponse> = Observable.create((observer) => {
const fr = new FileReader();
const errorBlob = err.error;
fr.readAsText(errorBlob, 'utf8');
fr.onloadend = () => {
const errMsg = JSON.parse(fr.result).message;
const msg = `In TtsService.getTts(${locale},${outputFormat}). ${errMsg}`;
observer.error(ErrorDataService.overLoadError(err, msg));
};
fr.onerror = (blobReadError) => {
observer.error(blobReadError);
};
fr.onabort = () => {
observer.error('aborted');
};
});
return $errBlobReader;
} else {
return throwError(ErrorDataService.overLoadError(err, message));
}
}));
Thanks! You really saved my day!

Categories

Resources