Passing an Array of Objects to an Endpoint using Angular - arrays

I have a post request where the format of the data getting posted, is like this:
{
"gallery": [{
"id": 606,
"status": 1,
"name": "00000000606.png",
"title": "splash.png",
"location": "",
"caption": "",
"type": "image/png",
"charset": "binary",
"tags": "",
"width": 2732,
"height": 2732,
"size": 476358,
"embed_id": null,
"user": 1,
"date_uploaded": "2019-09-26T05:22:31-04:00",
"storage_adapter": "local",
"url": "/storage/uploads/00000000606.png",
"thumbnail_url": "/storage/uploads/thumbs/606.png",
"old_thumbnail_url": "/storage/uploads/thumbs/00000000606-png-160-160-true.jpg",
"html": null
}, {
"id": 610,
"status": 1,
"name": "00000000610.png",
"title": "icon.png",
"location": "",
"caption": "",
"type": "image/png",
"charset": "binary",
"tags": "",
"width": 1024,
"height": 1024,
"size": 274477,
"embed_id": null,
"user": 1,
"date_uploaded": "2019-09-26T06:43:44-04:00",
"storage_adapter": "local",
"url": "/storage/uploads/00000000610.png",
"thumbnail_url": "/storage/uploads/thumbs/610.png",
"old_thumbnail_url": "/storage/uploads/thumbs/00000000610-png-160-160-true.jpg",
"html": null
}]
}
This then creates a gallery slide show once the data is sent.
In order to compile this array, I have firstly uploaded the images using a drag and drop feature. This uploads to a files directory endpoint and when successfully returned in the response is pushed to an array in local storage. The above data is the local storage object array. So looks fine until I try to send it back up.
Once the rest of the form is filled in, I send the form values using a post method. The data all seems to be shaped correctly, but the server responds with a 500 error.
the error (which won't be familiar to some) as I am using Directus Headless CMS
this error arises when posting from Postman, as I don't get much back in terms of an error message.
{
"success": false,
"error": {
"message": "File not found at path: "
},
"code": 0,
"class": "League\\Flysystem\\FileNotFoundException",
"file": "/homepages/5/d755856449/htdocs/demo/vendor/league/flysystem/src/Filesystem.php",
"line": 386
}
.html
this is the culprit in the view:
<label tooltip="Add images of the product here" placement="right" show-delay="500">Product Gallery<span
class="question">?</span></label>
<ngx-file-drop dropZoneLabel="Drop files here" (onFileDrop)="galleryFilesDropped($event)"
(onFileOver)="fileOver($event)" (onFileLeave)="fileLeave($event)">
<ng-template ngx-file-drop-content-tmp let-openFileSelector="openFileSelector">
Drag & Drop your Gallery Images onto Here.
<button class="update" type="button" (click)="openFileSelector()">Browse Files</button>
</ng-template>
</ngx-file-drop>
<label>Gallery Images</label>
<div class="gallery">
<ng-container *ngIf="!selectedGallery.length">
<div class="no_articles">
<img src="../../../assets/img/no_content-01.svg" alt="no-content icon">
<p>Currently, no gallery images exist, upload them above</p>
</div>
</ng-container>
<ng-container *ngFor="let image of selectedGallery">
<span>
<img class="placeholder" [src]="imageUrl + image.url" alt="selected image thumbnail">
<button class="delete" (click)="deleteImage()">Remove</button>
</span>
</ng-container>
</div>
and in the component.ts, this is the drop and post methods
image-drop method
public galleryFilesDropped(galleryImages: NgxFileDropEntry[], imageFile) {
this.galleryImages = galleryImages;
for (const droppedImage of galleryImages) {
if (droppedImage.fileEntry.isFile) {
const imageEntry = droppedImage.fileEntry as FileSystemFileEntry;
imageEntry.file((image: File) => {
let reader = new FileReader();
reader.readAsDataURL(image);
reader.onload = () => {
let data = reader.result;
let imageUpload = {
title: image.name,
name: image.name,
type: image.type,
size: image.size, data
}
this.configService.uploadImage(imageUpload)
.subscribe(
response => {
if (response) {
imageFile = response.data;
if (localStorage) {
var selectedImages;
if (!localStorage['selectedImages']) selectedImages = [];
else selectedImages = JSON.parse(localStorage['selectedImages']);
if (!(selectedImages instanceof Array)) selectedImages = [];
selectedImages.push(imageFile);
localStorage.setItem('selectedImages', JSON.stringify(selectedImages));
this.storageSubject.next(selectedImages);
}
}
}
)
}
});
} else {
const imageEntry = droppedImage.fileEntry as FileSystemDirectoryEntry;
console.log(droppedImage.relativePath, imageEntry)
}
}
}
the postProduct method
postProduct() {
let productCreate = {
product_category: this.selectedCategory, //posts fine
product_thumbnail: this.selectedImage,//posts fine
gallery: this.selectedGallery, <-- this doesn't send and breaks it
product_name: this.product_name,//posts fine
price: this.price,//posts fine
product_description: this.product_description,//posts fine
available_in_small: this.available_in_small,//posts fine
available_in_medium: this.available_in_medium,//posts fine
available_in_large: this.available_in_large,//posts fine
available_in_extra_large: this.available_in_extra_large,//posts fine
product_web_link: this.product_web_link,//posts fine
ad_click: this.ad_click//posts fine
}
this.storeService.createProduct(productCreate)
.subscribe(
response => {
if (response) {
this.product = response.data;
}
}
)
}
I have tried setting the gallery key value to:
gallery: {
data: JSON.parse(localStorage.getItem('selectedImages'))
},
and the same problem arises. The 500 error returns unknown, but from what I have learned from working this headless CMS, it will be due to the format of the data which is causing this.
I'm all out of ideas having tried a range of different ways to get this to work and I've now exhausted my subject knowledge and power of search to find a solution. Could some clever person possibly suggest what I'm doing wrong here?

Related

How to append the fields inside an array to a formdata in react?

I am a backend developer working mostly in Django-Rest-Framework. I have some issues while sending image in a post axios call. The frontend is sending objects like this here
{
"merchant": 2,
"category": [
7
],
"brand":7
, "name":"picture55test",
"best_seller":true,
"top_rated":false,
"collection":10,
"description":"abc",
"featured": false,
"availability": "in_stock",
"warranty": "no_warranty",
"rating":5,
"image":null,
"services": "cash_on_delivery",
"variants": [
{
"product_id": "OAXWRTZ_12C",
"price": "500.00",
"size": "not applicable",
"color": "not applicable",
"variant_image": null,
"quantity": 10,
"variant_availability": "available"
},
{
"product_id": "OGROUPIRZ_12C",
"price": "888.00",
"size": "not applicable",
"color": "not applicable",
"variant_image": null,
"quantity": 10,
"variant_availability": "available"
}
]
}
Now what I know is when we have to append a field to formdata we have to do like this:
handleSubmit = (e) => {
e.preventDefault();
console.log(this.state);
let form_data = new FormData();
form_data.append('image', this.state.image, this.state.image.name);
form_data.append('name', this.state.name);
form_data.append('services', this.state.services);
let url = 'http://localhost:8000/api/addproducts';
axios.post(url, form_data, {
headers: {
'content-type': 'multipart/form-data'
}
Now, as you can see I have an array of data being sent for variants. How to append the fields inside the array of variants just like I am appending the name of the product in the above snippet??
In backend, I have used JsonParser and Formparser because image file is being sent. I dont know if that helps or not, but I put it like below:
class ProductAddAPIView(CreateAPIView):
permission_classes = [IsAuthenticated]
parser_classes = [MultiPartParser,JSONParser,FormParser]
queryset = Product.objects.all()
serializer_class = AddProductSerializer
I have put the logic for creating the product objects as well as variants objects at the same time in serializer, but that is not necessary here I guess. I just need to know how to pass the image file which is inside an array, like variants array in the above data.

How to map a nested JSON response in React

I have to map the nested JSON result in React. The below one is the response I got as response from backend API.
{
"id": 2,
"name": "sanjna",
"email": "vv#gmail.com",
"address": "iiiii, hhh",
"gender": "1",
"tagline": "Friendly to all",
"description": "4 years experience in programming",
"languages": "English ",
"key_skills": [
{
"id": 1,
"name": "RUBY ON RAILS, HTML, BOOTSTRAP, JQUERY, REACT",
"relevant_experience": "4"
},
{
"id": 2,
"name": "ruby",
"relevant_experience": "2"
}
],
"certifications": [
{
"id": 1,
"name": "MCA",
"institution_name": "vvv unversity",
"certification_date": "20-12-2020",
"image": null
},
{
"id": 2,
"name": "HTML training",
"institution_name": "nnn unversity",
"certification_date": "20-12-2022",
"image": null
}
],
"educations": [
{
"id": 1,
"qualification": "MCA",
"course": "Masters Degree PG",
"institute": "kkk",
"ins_location": "jjjj",
"passing_year": "2015"
}
]
}
This is my React code to get this response
const [singleUserDetail, setsingleUserDetail] = React.useState('');
let logged_user_id = job_seeker.actable_id;
const getsingleUserDetails = (logged_user_id) => {
axios
.get(`http://localhost:3001/users/${logged_user_id}`, { withCredentials: true })
.then((response) => {
const singleUserDetail = response.data;
setsingleUserDetail(response.data)
console.log(response.data); //prints the above JSON results in console
})
.catch((error) => {
console.log(" error", error);
});
};
React.useEffect(() => {
getsingleUserDetails(logged_user_id);
}, [logged_user_id]);
When I prints {singleUserDetail.name} it gives me result sanjna
{singleUserDetail.email} it gives me result vvv#gmail.com
{singleUserDetail. address} it gives me result iiiii, hhh. from my above JSON result
But how to print keyskills, certifications and educations here with mapping. I'm a beginner in React.
Youu can do something like this, my example is very simple,but you can complicate this as much as you need, with conditions or loops in loops.
<div>
{singleUserDetail.name},{singleUserDetail.email},{singleUserDetail.address},{singleUserDetail.gender},{singleUserDetail.tagline},{singleUserDetail.description}, {singleUserDetail.languages}
</div>
{singleUserDetail.key_skills.map((skill)=>{
return(
<div key={skill.id}>
{skill.name}:{skill.relevant_experience}
</div>
);
})}
{singleUserDetail.certifications.map((certification)=>{
return(
<div key={certification.id}>
{certification.name},{certification.institution_name},{certification.certification_date}
</div>
);
})}
{singleUserDetail.educations.map((education)=>{
return(
<div key={education.id}>
{education.qualification},{education.course},{education.institute}
</div>
);
})}
For more information, React documentation

Extracting images data from Promise (ReactJS and Axios)

How do I get access to data stored as a Promise[] in ES6 array? I am loading an array from the backend and each object has a url for the image. So in order to render the image I have to async/await fetch the images for each object. Instead of returning a Base64 image, I get I promise with the image embeded deep in the promise. I need a way to read the image data. See image below for return object structure.
Please note that i use axios in the background and NOT the Fetch API
Below are the functions and service methods used to load the list and then the images in 2 steps.
1.1 Axios service method
listAllItems() {
return axios.get(API_URL + "docman/items/list/all");
}
1.2 ReactJS main function
async componentDidMount() {
try {
const items = await DocmanService.listAllItems();
const itemsData = items.data;
const data = await itemsData.map(item => {
const image = this.loadImage(item.image);
return { ...item, image: image }
})
this.setState({ items: data });
} catch (e) {
console.log(e);
}
}
2.1 Axios images service method
loadImage = (url) => {
return axios.get(API_URL + url, { responseType: 'arraybuffer' });
}
2.2 ReactJS image loader function
async loadImage(imageUrl) {
try {
return await ImageService.loadImage(imageUrl)
} catch (e) {
return '';
}
}
3.1 Json list fetched from backend
[
{
"id": "1",
"uuid": "1c0a33af-4e78-4823-b84e-f3b5464db2af",
"identifier": "EN ISO 8402",
"title": "EN ISO 8402 Quality Management - Vocabulary",
"folder": "e347fef9-0a76-4e62-b7f2-c78e9f88355b",
"media": "FILE",
"path": "document/id/105",
"image": "image/id/106",
"format": "PDF",
"authors": "",
"publishers": "",
"created": "2020-09-22T14:56:31.316+00:00",
"published": null,
"version": "1994",
"status": null
},
{
"id": "2",
"uuid": "16a0e658-b444-4b60-bf18-ba2786d5fb00",
"identifier": "ISO 14001",
"title": "ISO 14001 Environmenatl Management Systems - Requirements with Guidance for Use",
"folder": "e347fef9-0a76-4e62-b7f2-c78e9f88355b",
"media": "FILE",
"path": "document/id/107",
"image": "image/id/108",
"format": "PDF",
"authors": "",
"publishers": "",
"created": "2020-09-22T14:56:31.659+00:00",
"published": null,
"version": "2004",
"status": null
},
-
-
]
try doing image.then((data) => { // console.log(data) })
When you setState you are setting the new state with a list of objects with an image value that is a promise. Shouldn't you update the state only when at least one of the promise resolved to a real image?
Couldn't you do something like
this.loadImage(item.image).then((imageData=>setState(appropriate State)))?

Dealing duplicate image data in React Native

I'm building 'Comments Detail page' which is a list view for comments in a single post (basically it's just facebook comments page).
I generated this JSON response data below, and as you can see, there are duplicate image urls. It means that if same user comments 100 times on a post, it needs to get image data from AWS 100 times rather than 1 time.
Maybe it's over-engineering? How do you guys deal with this?
Here is JSON data
{
"comments": [{
"id": 4,
"user": {
"image": "https://xxx.s3.amazonaws.com:443/-",
"id": 1,
"username": "jbaek73"
},
"content": "Edited!",
"publish": "2017-09-18T12:11:41.002838Z",
"updated": "2017-09-19T08:16:25.408756Z",
"reply_count": 1
},
{
"id": 13,
"user": {
"image": "https://xxx.s3.amazonaws.com:443/-",
"id": 1,
"username": "jbaek73"
},
"content": "Neaa!",
"publish": "2017-09-18T14:12:51.876523Z",
"updated": "2017-09-18T14:12:51.876600Z",
"reply_count": 0
},
{
"id": 14,
"user": {
"image": "https://xxx.s3.amazonaws.com:443/random",
"id": 5,
"username": "koreana"
},
"content": "Newa!",
"publish": "2017-09-19T08:16:35.190351Z",
"updated": "2017-09-19T08:16:35.190398Z",
"reply_count": 0
},
In this case, i would create an image object with all the required images and the user id as key:
randomFuntionName() { //you can call after you get your json
var img = []
comments.forEach((element) => { //comments are comming from your json btw
if (img[element.user.id] == null) {
img[element.user.id] = require(element.user.image)
}
})
this.setState({img})
}
render() {
//this part is only for example, you need to dynamicaly change userID
return (<Image source={this.state.img[userId]}/>)
}
This should do the work, but didn't tested it in app.

Asynchronous Angular-bootsrap-UI typeahead: select directive issue

My application is using the Angular-Bootstrap-UI-Typeahead feature for auto complete.
As the user types, i'd like to be able to call an API & return similar strings.
I've followed the guidance here, and everything works fine with the out of box Google API.
I've also successfully swapped in my own API: I am able to call the API, get the data, and log it in the correct format in my browser console.
However, I constantly get "no results found" from the text box. I suspect this may be a problem with the select directive, but i am stumped.
I would greatly appreciate any guidance on this!
Here is some code:
UI (content.html)
<h4>biz results</h4>
<pre>Model: {{user.orgName | json}}</pre>
<input type="text"
ng-model="user.orgName"
placeholder="Locations loaded via $http"
uib-typeahead="obj for obj in getLocation($viewValue)"
typeahead-loading="loadingBiz"
typeahead-no-results="noBiz" class="form-control"
typeahead-wait-ms="700">
<i ng-show="loadingBiz" class="glyphicon glyphicon-refresh"></i>
<div ng-show="noBiz">
<i class="glyphicon glyphicon-remove"></i> No Results Found
</div>
Angular (script.js)
$scope.getLocation = function(val) {
var bizRequest = $http.post('/sample', {
// var bizRequest = $http.post('/biz', {
orgName: val,
limit: 5
}
).success(function(response){
console.log(response)
//console.log('Biz response: ' + JSON.stringify(response))
//console.log(response.data.fields.map(item))
var bizArray = response.data.fields.map(function(item){
return item.fields.orgName;
});
console.log(bizArray);
return bizArray;
});
console.log("Biz Request /////// " + JSON.stringify(bizRequest))
return bizRequest
};
Node API (app.js)
app.post('/sample', function(req, res){
var resp = {
"success": true,
"data": {
"fields": [{
"fields": {
"scid": "1111",
"orgName": "1111",
"countryCode": "1",
"countryName": "1",
"cityName": "1",
"addressLine": "1111"
},
"matchedRule": {
"duplicateLevel": "POTENTIAL_MATCH",
"id": "18",
"rank": "1"
}
}, {
"fields": {
"scid": "2222",
"orgName": "2222",
"countryCode": "22",
"countryName": "22",
"cityName": "22",
"addressLine": "2 22"
},
"matchedRule": {
"duplicateLevel": "POTENTIAL_MATCH",
"id": "18",
"rank": "1"
}
}]
},
"errors": [],
"warnings": [],
"infoMessages": []
}
res.send(JSON.stringify(resp))
})
You have to return promise from getLocation method while dealing asynchronous typeahead. So don't use .success there which would break promise chain. Instead use .then which would help you to chain promise and you can return data from .then to pass it to typeahead
$scope.getLocation = function(val) {
var bizRequest = $http.post('/sample', {
// var bizRequest = $http.post('/biz', {
orgName: val,
limit: 5
}
).then(function(data){
response = data.data; //<-- take data in response.
console.log(response.data)
//console.log('Biz response: ' + JSON.stringify(response))
//console.log(response.data.fields.map(item))
var bizArray = response.data.fields.map(function(item){
return item.fields.orgName;
});
console.log(bizArray);
return bizArray;
});
console.log("Biz Request /////// " + JSON.stringify(bizRequest))
return bizRequest
};

Resources