Sending json object as json array to an API - arrays

I have an API that accepts data format as [ { "record_id": "TestID3" } ]. I am trying to send record_id field using the form below in my angular project:
html:
<input id="record_id" type="text" class="form-control" [(ngModel)]="member.record_id" name="record_id" #record_id="ngModel" placeholder="Enter Record ID">
component.ts:
export class MembersAddComponent implements OnInit {
member: Array<Object> = [];
constructor(private service: DataService ) { }
ngOnInit() {
}
submit() {
this.service.importRecord(this.member).subscribe(member => {
this.member = member;
}, error => {
console.log(error);
});
}
}
And my service.ts:
importRecord(data): Observable<any> {
const formData = new FormData();
formData.append('token', this.token);
formData.append('content', this.content);
formData.append('format', this.format);
formData.append('returnFormat', this.returnFormat);
formData.append('type', this.type);
formData.append('overwriteBehavior', this.overwriteBehavior);
formData.append('forceAutoNumber', this.forceAutoNumber);
formData.append('data', data);
formData.append('returnContent', this.returnContent);
return this.http.post(this.baseUrl, formData).map(res => res.json())
.catch(this.handleError);
}
The error that I get is below:
{"error":"The data being imported is not formatted correctly. The JSON must be in an array, as in [{ ... }]."}
I also tried member:any = {}, member:Object = {}; but I got the same error. I am thinking that I am unable to format my member object as requested format. But I couldn't make it as desired format.

[ { "record_id": "TestID3" } ]
That is an array, containing a single element, which is an object.
member: Array<Object> = [];
that defines an array with no element at all.
[(ngModel)]="member.record_id"
That will try to read and write the property record_id of member, which is an array. It will not magically add an element to the array and set its property.
So what you need is an object that will be populated by the form. And then you need to put that object into an array before to send the array to the API.
Start by defining an interface to describe your object:
interface Member {
record_id: string;
}
Then use one as the model for your form:
member: Member = {
record_id: '';
};
...
[(ngModel)]="member.record_id"
Then put that member into an array before sending it:
submit() {
const data: Array<Member> = [this.member];
this.service.importRecord(data)...

It's difficult to tell if this is due to an incorrectly formatted response from the POST or the body of the POST.
Things you can do:
Check the network tab in Chrome to verify that the request is being sent, it's content is valid JSON (use an online validator)
Check your API backend to see if the data you're sending is being saved, if so the error is with the format of the JSON in your response.
Verify in Chrome that the response data in the network request is valid JSON.
If all of these are true, you may need to consider using headers such as {requestType: 'json'} as detailed in the Angular docs here: Request/Response Headers
If these are not true, then you will need to change the model of the object you are sending to reflect the object which is expected.

Related

How to use custom field in react admin, insted of { data: [...] }

I'm new in react-admin and I'm trying to create a new admin panel for my old API.
So when my data provider do API calls it causes me this error:
The response to 'getList' must be like { data : [...] }, but the received data is not an array. The dataProvider is probably wrong for 'getList'
The responses of my old API has various data fields like { 'posts': [] } or { 'users': [] }. How can I use these name of fields instead of { 'data': [] } ?
The 'data' in this case just refers to the type of information that should be retuned, not the name of the object.
Within your API, you can simply return a list in the following form:
const posts = [
{
"id":1,
"name":"post1"
},
{
"id":2,
"name":"post2"
},
];
return JSON.stringify(posts);
Then return that 'posts' object in your response and don't forget to set the expected ContentRange headers.
Not sure what language you are using, but the principle above should be easy enough to follow and apply in any language.

Find Object Array and its Properties from Ajax Post Request

I'm sending an AJAX request to an internal PHP and receiving back an object. The object has properties of "data" and "status", yet when I try to access them, it does not return anything. How can I show each property separately?
For reference, the returned obj array is:
{"data:[{"tagId":"8787","tagDescription":"001","tagMin":"0","tagMax":"100"},{"tagId":"8729","tagDescription":"1","tagMin":"44","tagMax":"555"}]
function GetAll() {
var PostRequest ={};
PostRequest['tagId']= 'all';
$.post('php here',PostRequest,ShowAllTags);
}
function ShowAllTags( responseData, responseStatus ) {
console.log(responseStatus);
var tagData = {};
tagData = responseData;
console.log(tagData['data']);
}
So according to the above comment mention by me, The problem is with json object, in response.
So first of all fix that,
Generic solution of this problem will be;
var obj = [{"tagId":"8787","tagDescription":"001","tagMin":"0","tagMax":"100"},{"tagId":"8729","tagDescription":"1","tagMin":"44","tagMax":"555"}];
obj.forEach(function(value, index){console.log(value.tagId)});
This might help, how to get value of each property

How to get data in all the pages of an API http request using observables in Angular?

I am making an http.get request to an API to get data. The API uses pagination and contains 30 entries/page. It also provides information about next page and last page along with respective links (also prev page and first page when applicable) in the response header links.
The Link header includes pagination information:
<https://api.example.com/user?page=2>; rel="next",
<https://api.example.com/user?page=10>; rel="last"
The JSON object in response.body
[
{
userId: 1,
name: 'John',
created_at: "2015-10-13T03:10:43Z",
},
{
userId: 2,
name: 'Jane',
created_at: "2019-02-15T13:37:03Z",
}
....
]
I am using angular 6 and trying to accumulate the data by making subsequent http.get calls. I have tried to use array method push() for subsequent data. But the since the typeof resp.body is object it is not working.
userData: any[];
getData(url: string) {
this.http.get(url, {observe: 'response'});
.subscribe((resp) => {
this.userData.push(resp.body);
}
Error message: TypeError: Cannot read property 'push' of undefined
The userData should contain array of data received from http.get requests which is iterable.
You can't .push to an uninitialized array.
Try doing this:
userData = [];
as mentionned in previous answer you should initialize your array before you can use push() on it.
But if I understand well you receive an array of user for each response. By using push on each response you will obtain an array of array.
You should either use concat to merge the two arrays or use a foreach on the response and then push.
also I would recommend you using interfaces or classes and try to avoid any
interface UserData {
userId: number;
name: string;
created_at: string;
}
userData: UserData[] = [];
getData(url: string) {
this.http.get(url, {observe: 'response'})
.subscribe((resp) => {
resp.body.forEach((user: UserData) => {
this.userData.push(user);
});
});
}
userData: any[] = [];
userData is not initialized which is throwing this error. Try it with empty Array.
Initialize the array at first then push, The following code looks like this.
userData: any[] = [];
getData(url: string) {
this.http.get(url, {
observe: 'response'
});
.subscribe((resp) => {
// this.userData = [];
this.userData.push(resp.body);
}

How to loop through an object and push into an array

What I'm working with
angular2
firebase
What I have
A returned object
Each item in the object has a URL property
What I would like to do
Loop through each of the items in the object and get the URL property
Pass that into a firebase storage variable
Push the URL property into an array to make available for my HTML
note: I have this working by hard coding a url, I just need some assistance looping through the object to get the other urls in the object.
Component.ts
'this.imagesToDisplay' will return an object of object (image below)
this.activatedRoute.data
.subscribe((
data: { issueData: any, issueImageData: any }) => {
this.issueToDisplay = data.issueData;
this.imagesToDisplay = data.issueImageData;
this.testing(this.imageToDisplayArray);
});
Comnponent TS - Testing method
So this is hardcoded and pushes the hardcoded url into the array and displays correctly through databinding with the HTML. Cool. However, I would like to loop through the 'imagesToDisplay' object and get both returned urls.
testing(imageToDisplayArray) {
// this works with one url
var storage = firebase.storage().ref().child("image/-Kosd82P-bmh4SFetuf3/-Kosd8HhGmFiUhYMrlvw/30DD9F39-4684-4AA0-9DBF-3B0F0C3450A4.jpg");
storage.getDownloadURL().then(function(url) {
imageToDisplayArray.push(url);
console.log(imageToDisplayArray);
});
}
Any help here would be massively appreciated.
Note: I think this question here is what I'm trying to do, I'm just not sure how to integrate that into my current code. Any help would be awesome.
Stack Overflow question on firebase storage looping
UPDATE
So, I'm incredibly close now. I just have one issue. The code below loops through the returned data and extract the URL properties. I use the url properties to connect to the firebase storage and return the download URLs. Both of these are logged to the console! Awesome. I now have the URLs i needed! The issue I'm having is, it will only let me push these values to a local array. In this instance 'var array'. I need to push to an array that's outside of the 'activatedRoute' 'method'. Anytime I do, it returns as undefined.
this.activatedRoute.data
.subscribe((
data: { issueData: any, issueImageData: any }) => {
this.issueToDisplay = data.issueData;
this.imagesToDisplay = data.issueImageData;
var array = [];
data.issueImageData.forEach(image => {
// Reference to the image URL
var image = image.url;
// Firebase storage
var storage = firebase.storage();
// Path reference
var imagePathReference = storage.ref().child(image);
// Get Download URL
imagePathReference.getDownloadURL().then(function (url) {
console.log(url);
array.push(url);
})
});
});
I would recommend you to use the features rxjs provides you:
this.activatedRoute.data.switchMap(data => {
let parsedData = {
issueToDisplay: data.issueData,
imagesToDisplay: data.issueImageData
}
let imageUrls$ = data.issueImageData.map(image => {
var imagePathReference = storage.ref().child(image);
return Observable.fromPromise(imagePathReference.getDownloadURL())
});
return Observable.forkJoin(imageUrls$).map((...urls) => {
return Object.assign(parsedData, { urls });
})
}).subscribe(data => {
/*
data looks like this:
{
issueToDisplay: any,
imagesToDisplay: any,
urls: string[]
}
*/
});
If I'm correct, you're looking for a solution to map an array-like object of objects to an actual array of objects.
Here is a way to do just that:
var object = {
'0': {
"url": "url1",
"name": "obj1",
"data": 1234
},
'1': {
"url": "url2",
"name": "obj2",
"data": 5678
},
'length': 2
}
var sliced = Array.prototype.slice.call( object, 0 );
console.log(sliced)
Couple remarks:
If you wonder how this works, check this post.
Alternative syntax that you could encounter looks like [].slice.call()
If you want to perform array-like operations, you can probably do that right away with Array.prototype.<METHOD>.call(object, <CALLBACK>
For example:
Array.prototype.map.call(object, function(el) { // return your enhanced element })
So, this works. Not entirely sure how clean it is. But it works.
this.activatedRoute.data
.subscribe((
data: { issueData: any, issueImageData: any }) => {
this.issueToDisplay = data.issueData;
this.imagesToDisplay = data.issueImageData;
var localImageArray = [];
data.issueImageData.forEach(image => {
// Reference to the image URL
var image = image.url;
// Firebase storage
var storage = firebase.storage();
// Path reference
var imagePathReference = storage.ref().child(image);
// Get Download URL
imagePathReference.getDownloadURL().then(function (url) {
localImageArray.push(url);
})
this.getIssueImageArray(localImageArray);
});
});
}
// Get Image Array
getIssueImageArray(array) {
this.imageToDisplayArray = array;
}

How to make $resource accept array of strings (AngularJS)

I would like to make a request to a REST-service in which the query parameters contain an array of strings:
productRestService.getProductsInfo(productIdsArray,"id,name,rating").$promise.
then(function(productData) { // success: Produktdaten auslesen
updateProductList(productData);
}, function (error) {
console.log("Status: " + error.status);
});
The Resource-Service is as follows:
productRestService.getProductsInfo = function(productIds, properties) {
console.log('productRestService.getProductsInfo(): productIds' + productIds);
var productInfoResourceData;
var ProductInfoResource = $resource('/rest/products/productsInfo/:productIds/:properties',
{
productIds:'#productIds',
properties:'#properties'
}
);
productInfoResourceData = ProductInfoResource.query(
{
productIds: productIds,
properties: properties
}
);
return productInfoResourceData;
}
Calling the service results to an 404-Error, because the default behaviour of the $resource object is that it expects an array of an object when "query" is used.
How can I achieve that my $resoure-service will accept an array of strings? I tried to use "transformRequest" (see snippet below), but that did not work either.
{
query: {
method: 'GET',
isArray: true,
transformResponse: function (data, headers) {
var tranformed = [];
[].forEach.call(eval(data), function (d) {
tranformed.push({ name: d });
});
return tranformed;
}
}
}
A console.log within the function of the REST service productService.getProductsInfo shows the correct data that the service received:
["212999cc-063b-4ae8-99b5-61a0af39040d","17e42a28-b945-4d5f-bab1-719b3a897fd0","9307df3e-6e7a-4bed-9fec-a9d925ea7dc0"]
The URL is correct with the other REST-URLS and should look this way (and is being concatenated to the domain accordingly):
'/rest/products/productsInfo/:productIds/:properties'
EDIT:
The other functions within the productService responds in order, they do not use arrays but JSON objects and do not show unexpected behaviour.
(This was originally a comment, but it needed cleanly formatted code samples.)
I suspect your :productIds template parameter is getting filled into the template as "[object Object]". I've only seen your template URL, not the actual constructed URL, so I can't be sure.
If your server is expecting a URL where the :productsIds template parameter is JSON, like for example ---
rest/products/productsInfo/["id1","id2","id3"]/{"prop1":true,"prop2":false}
--- then try editing your getProductsInfo definition to something like this:
productRestService.getProductsInfo = function (productIds, properties) {
var ProductsInfo = $resource('/rest/products/productsInfo/:productIds/:properties', {
productIds: function () {
return angular.toJson(productIds);
},
properties: function () {
return angular.toJson(properties);
}
});
return ProductsInfo.query();
}
(Fair warning, I didn't test this code. It's just a quick edit of your example.)
This way, you're making sure that the parameter values are converting to the JSON that the server expects (if the server is expecting JSON in the URL, that is).

Resources