Iterate through JSON object in angular 6 - json

I am new to Angular and probably this might be a silly question. I am trying to get an api response and save it into an array. My API response looks like :
[
{
"name1": {
"name": "name1",
"api": {
//somedata
},
"t1p": {
//somedata
}
}
},
{
"name2": {
"name": "name2",
"api": {
//somedata
}
},
"t1p": {
//somedata
}
}
}
]
I get the response from the code
var data = [];
makeRequest(): void {
this.http
.get(this.URL1)
.subscribe((res: Response) => {
this.data = res;
console.log(this.data);
}, err => console.log(err));
}
Now I want to fetch the "name" value from each of the JSON object. I tried doing this:
var ids:string = [];
for(let result of this.data){
ids.push(result.name);
console.log("Added"+result.name);
}
But I am not able to achieve the same. Can anyone tell me what is wrong with the same.

You can implement it with .map and Object.keys()
const result = data.map(item => Object.keys(item)[0]);
console.log(result); // ['name1', 'name2']
If you want to perform that method to your http call. You can do so by:
this.http
.get(this.URL1)
.pipe(map(res => res.map(item => Object.keys(item)[0])))
.subscribe((res: Response) => {...});

Try this !
for(let i = 0; i < this.data.length; i++ )
{
for(let key of this.data[i])
{
if(this.data[i][key].hasOwnProperty("name"))
ids.push(this.data[i][key][name]);
}
}
As your object lies inside another object with key as name.

makeRequest(): void {
this.http
.get(this.URL1)
.pipe((response) => {
response.map((re,index)=> re['name'+(index+1)]['name'])
})
.subscribe((res: Response) => {
this.data = res;
console.log(this.data);
}, err => console.log(err));
}
I gave the solution by looking at your response API. Now in the subscriber, you will get the only name.

Related

Retrieving data from MongoDB ánd MySQL simultaneously

I am trying to retrieve data from my MongoDB database which stores chat conversations. This works fine and returns what I want. However, I only save userIDs in MongoDB, so I need to query profile picture, username etc from my MySQL database. I tried the following:
app.get('/api/retrieveAllChats', (req, res) => {
var Conversation = mongoose.model('Conversation', ConversationSchema);
var ChatMessage = mongoose.model('Message', ChatMessageSchema);
var userID = req.query.userID.toString()
var members = []
var conversationData = []
var retrieveAllChats = new Promise(function(resolve, reject) {
Conversation.aggregate([{ $match: { "members.uID": userID } }, { $lookup: { foreignField: "c_ID", from: "messages", localField: "_id", as: "messages" } }, { "$unwind": "$messages" }, { "$sort": { "messages.t": -1 } }, { "$group": { "_id": "$_id", "lastMessage": { "$first": "$messages" }, "allFields": { "$first": "$$ROOT" } } }, { "$replaceRoot": { "newRoot": { "$mergeObjects": [ "$allFields", { "lastMessage": "$lastMessage" } ] } } }, { "$project": { "messages": 0 } }], function (err, conversations) {
if (err) return handleError(err);
conversations.forEach((conversation, i) => {
return new Promise(function (resolveConversations, rejectConversations) {
var membersPromise = conversation.members.forEach((member, x) => {
return new Promise(function (resolveUserData, rejectUserData) {
getUserData(member["uID"], function(userData) {
members.push({userID: member["uID"], joinDate: member["j"], userName: userData["userName"], userDisplayName: userData["userDisplayName"], userVerified: userData["userVerified"], userProfilePicURL: userData["userProfilePicURL"]})
console.log("userData: ", userData)
conversations[i].members[x].userData = userData
conversationData = conversations
resolveUserData({userID: member["uID"], joinDate: member["j"], userName: userData["userName"], userDisplayName: userData["userDisplayName"], userVerified: userData["userVerified"], userProfilePicURL: userData["userProfilePicURL"]})
})
})
})
resolveConversations()
})
})
resolve()
})
}).catch(error => {
console.log(error)
res.json({ errorCode: 500 })
})
retrieveAllChats.then(function() {
res.header("Content-Type",'application/json');
res.send(JSON.stringify(conversationData, null, 4));
})
})
However, the conversationData array is always empty. So I need a way to resolve the retrieveAllChats promise and pass the data I added to the existing conversations object to return it with all information I need. Any ideas on how I can do this? (getUserData is a function to retrieve the MySQL data, this one works fine and returns what I want)
You are trying to do async operation inside forEach which wouldn't work. You need to either use for...of or Promise.all.
Also, you can make this code much cimpler by using .exec() at the end of running any query or aggregation as that is supported by mongoose. Something like this should work. Make sure you change your routte line to this to tell it is an async function
app.get("/api/retrieveAllChats", async (req, res) => {
core logic
const conversions = await Conversation.aggregate([{"$match": {"members.uID": userID}}, {"$lookup": {"foreignField": "c_ID", "from": "messages", "localField": "_id", "as": "messages"}}, {"$unwind": "$messages"}, {"$sort": {"messages.t": -1}}, {"$group": {"_id": "$_id", "lastMessage": {"$first": "$messages"}, "allFields": {"$first": "$$ROOT"}}}, {"$replaceRoot": {"newRoot": {"$mergeObjects": ["$allFields", {"lastMessage": "$lastMessage"}]}}}, {"$project": {"messages": 0}}]);
for(const conversation of conversations) {
for(const member of conversation.members) {
// add your promise call here and either await it or use then to get the promise value.
}
}

Angular HttpClient-subscribe select property from data

I'm really sure about, that this question is answered multiple times in here. But I can't find them/don't knwo which terms to search for.
I've got a JSON-file looking like that:
{
"pages": [{
"displayname": "PageA",
"url": "http://google.de",
"icon": "iconZ"
},
{
"displayname": "PageB",
"url": "http://www.pageb.co.uk",
"icon": "iconY"
}
],
"icons": [{
"alias": "iconZ",
"filename": "iconZ.svg"
},
{
"alias": "iconY",
"filename": "iconY.svg"
}
]
}
Now I'm using the HttpClient (here called httpService) to get the data from the file.
this.httpService.get('./assets/pageconfig.json').subscribe(
data => {
this.arrAdress = data as string[];
},
(err: HttpErrorResponse) => {
console.log(err.message);
}
);
I want to use the content of pages in my ngFor in the Frontend and I want to get an array of the icon-content for use in the Backend. How can I select/split the data by using the properties.
Thanks for your help
Elias
Considering your pageconfig.json is used in both front and backend, and that you just need the "pages" attribute in your angular app, you may get it this way:
this.httpService.get('./assets/pageconfig.json').subscribe(
data => {
this.arrAdress = data.pages;
},
(err: HttpErrorResponse) => {
console.log(err.message);
}
);
You don't need to cast the data type.
You could also use the rxjs observable map chaining to parse your data and get only what interests you:
import { map } from 'rxjs/operators';
this.httpService.get('./assets/pageconfig.json')
.pipe(map(data => data.pages))
.subscribe(pages=> {
this.arrAdress = pages;
}.catch((err: HttpErrorResponse) => {
console.log(err.message);
});
I hope this is what you were looking for.
Need to remove string[], instead use Array of object or any.
this.httpService.get('./assets/pageconfig.json').subscribe(
data => {
this.arrAdress = data;
},
(err: HttpErrorResponse) => {
console.log(err.message);
}
);
sendData(icon){
const matched = this.arrAdress.icons.filter(iconObj => iconObj.alias === icon);
console.log(matched);
}
**Template:**
<div *ngFor="let adress of arrAdress?.pages;" (click)="sendData(adress.icon)">
<span>{{adress.displayname}}</span>
</div>
You have two solutions here to solve this issue
Suppose httpClient.Delete() option returns back you an observable object with employeeId as property in it.
Solution 1 (example)
Create an local variable and assign data to it using let statement (e.g. let response: any = data;).
delete(employee: any) {
this.employeeService.deleteEmployee(employee.id)
.subscribe(
data => {
let response: any = data;
// now you can use response.employeeId
},
(error) => {
console.log(error)
},
() => {
console.log("The operation has been completed")
}
);
}
Solution 2 (example)
Assign type any (e.g. (data : any) to received response
delete(employee: any) {
this.employeeService.deleteEmployee(employee.id)
.subscribe(
(data: any) => {
// now you can use data.employeeId
},
(error) => {
console.log(error)
},
() => {
console.log("The operation has been completed")
}
);
}

Angular 5 Observable mapping to Json array

My backend return this :
{
"FirstResponse": [
{
"MyField1": "AAA",
"MyField2": "AAAAAAA"
},
{
"MyField1": "BBB",
"MyField2": "BBBBBBB"
},
{
"MyField1": "CCC",
"MyField2": "CCCCC"
}
],
"SecondResponse": [
{
"FirstName": "FirstNameA",
"LastName": "LastNameA"
},
{
"FirstName": "FirstNameB",
"LastName": "LastNameB"
}
]
}
I'd like map FirstReponse to a variable and SecondResponse to another variable.
How can I adapt the code below ?
search(): Observable<any> {
let apiURL = `......`;
return this.http.get(apiURL)
.map(res => res.json())
}
Update : Excepted result
In one variable this :
[
{
"MyField1": "AAA",
"MyField2": "AAAAAAA"
},
{
"MyField1": "BBB",
"MyField2": "BBBBBBB"
},
{
"MyField1": "CCC",
"MyField2": "CCCCC"
}
]
In a second :
[
{
"FirstName": "FirstNameA",
"LastName": "LastNameA"
},
{
"FirstName": "FirstNameB",
"LastName": "LastNameB"
}
]
You could create a new file which exports the model class and then assign it to the returning Observable type. Something like:
new model.ts file
class FieldModel {
Field1: string;
Field1: string;
}
export class valuesModel {
MyValues: Array<FieldModel>;
}
on the service.ts
import { valuesModel } from 'model';
search(): Observable<valuesModel> {
let apiURL = `https://jsonplaceholder.typicode.com/users`;
return this.http.get(apiURL)
.map(res => res.json())
}
Please check this approach, use
import { Http, Response} from '#angular/http';
import { Observable } from 'rxjs/Observable';
public search(){
let apiURL = `https://jsonplaceholder.typicode.com/users`;
return this.http.get(apiURL)
.map((res: Response)=> return res.json();)
.catch((error: Response) => {
return Observable.throw('Something went wrong');
});
}
for this search() method you can subscribe from your component.
And if you want to map output into respected modal then please provide format of same.So that i can help
I don't crealry understan what you wanna get because you not provide example result,
however try this - change line:
.map(res => res.json())
to
.map(res => res.json().MyValues )
using this you will get at the top level similar array like in link you provided in comment below you question: https://jsonplaceholder.typicode.com/users
UPDATE (after question update 9.10.2018)
Currently .map(res => res.json()) returns object that has two fields (variables) "FirstResponse" and "SecondResponse". You can have acces to it by for example (I write code from head):
public async loadData()
{
let data = await this.yourService.search().toPromise();
let firstVariable = data.FirstResponse;
let secondVariable = data.SecondResponse;
...
}
So as you describe in your question/comments in loadData() you get result in two variables as you want.
Or alternative answer - if you wanna do this inside search() then you can do that in such way for example:
search(): Observable<any> {
let apiURL = `......`;
return this.http.get(apiURL)
.map( (res) => {
let data = res.json();
return {
firstVariable: data.FirstResponse,
secondVariable: data.SecondResponse,
}
})
}

How to pass dynamic attribute/parameter to openDialog?

I need to pass the following ID: 59dc921ffedff606449abef5 dynamically to MatDialog. For testing proposes I'am using it as hard coded ID.
Unfortunately all my searches and tries failed and I can't get the id dynamically into the function call. I tried also the #input feature, but it didn't help.
edit-dilog.component.ts:
export class EditDialogComponent implements OnInit {
dialogResult:string = '';
constructor(public dialog:MatDialog, public loginService:LoginService ){ }
ngOnInit() {}
openDialog() {
this.dialog.open(EditUserComponent, { data: '59dc921ffedff606449abef5' })
.afterClosed()
.subscribe(result => this.dialogResult = result);
}
}
edit-user.component.ts:
export class EditUserComponent implements OnInit {
public message:any [];
public resData: {};
constructor(public thisDialogRef: MatDialogRef<EditUserComponent>,
#Inject(MAT_DIALOG_DATA) public data: number,
public loginService: LoginService) { }
ngOnInit() {
this.loginService.getSingleUser(this.data)
.subscribe(data => {
this.resData = JSON.stringify(data);
})
}
onCloseConfirm() {
this.thisDialogRef.close('Confirm');
}
onCloseCancel() {
this.thisDialogRef.close('Cancel');
}
}
The ID is coming from JSON Response in a service login-service.ts:
getSingleUser(id) {
return this.http.get(environment.urlSingleUsers + '/' + id, this.options)
.map(res => {
console.log('RES: ' + JSON.stringify( res.json() ) );
return res.json();
}).catch( ( error: any) => Observable.throw(error.json().error || 'Server error') );
}
extractData(result:Response):DialogUserData[] {
return result.json().message.map(issue => {
return {
ID: issue._id,
Email: issue.email,
Name: issue.fullName
}
});
}
And here is where I do the call of openDialog():
<i class="material-icons" (click)="openDialog()">create</i>
For more clarification here is how the JSON Response comes:
"message": [
{
"_id": "59415f148911240fc812d393",
"email": "jane.doe#foo.de",
"fullName": "Jane Doe",
"__v": 0,
"created": "2017-06-14T16:06:44.457Z"
},
{
"_id": "5943b80be8b8b605686a67fb",
"email": "john.doe#foo.de",
"fullName": "John Doe",
"__v": 0,
"created": "2017-06-16T10:50:51.180Z"
}
]
I just did something similar, though I'm a little bit confused by how you name the components (seems should be the other way around).
You can try: fetch the data (user) first and then (actually) open the dialog in your controlling component:
edit-dialog.component.ts:
openDialog(id: string) {
this.loginService.getSingleUser(id)
.subscribe(user=> {
const dialogRef = this.dialog.open(EditUserComponent, {
data: user
});
dialogRef.afterClosed().subscribe(result => {
console.log(`Dialog result: ${result}`);
});
});
}
You can then access the dialog data (user) to render the dialog view:
edit-user.component.ts:
ngOnInit() {
console.log(this.data);
}
In this way, you can pass the id dynamically:
<i class="material-icons" (click)="openDialog(id)">create</i>
where the id can be a member of your controlling component.

Observable from a RESTful paged collection

On one hand, I have a RESTful HAL HATEOAS collection which looks like this :
{
"page": 1,
"limit": 10,
"pages": 18,
"total": 174,
"_links": {
"self": { "href": "/users?page=1&limit=10" },
"first": { "href": "/users?page=1&limit=10" },
"last": { "href": "/users?page=18&limit=10" },
"next": { "href": "/users?page=2&limit=10" }
},
"_embedded": {
"users": [
{
"name": "bob",
"_links": { "self": { "href": "/users/1" } }
},
...
]
}
}
On the other hand, I have an Angular 2 app.
public getUsers(uri: string = this.baseURI): Observable<User> {
return this.http.get(uri)
.map(res => res.json()._embedded.users as User[])
.flatMap(d => d) // Transform the flux of arrays in flux of users
.catch(this.handleError);
} // Get only the 10th first users
What I'm trying to do have an observable of Users which will append data while _links.next != null
Modified service
public getUsers(uri: string = this.baseURI): Observable<User> {
return this.http.get(uri)
.do(res => {
const uri = JSON.parse(res._body)._links.next.href;
this.nextUri = uri ? uri : null;
})
.map(res => res.json()._embedded.users as User[])
.flatMap(d => d) // Transform the flux of arrays in flux of users
.catch(this.handleError);
}
Recursive function
loadAll(uri: string) {
read(uri)
.subscribe(
user => {
this.stockedUsers.push(user);
},
error => console.log(error),
() => {
if (this.nextUri) {
this.loadAll(this.nextUri);
}
}
);
}
Does someone know how to achieve this properly ?
I want to keep thes advantages of the RxJS flux.
UPDATE/ANSWER
Silly me ! I think I answered myself. Maybe this will help others :
public read(uri: string = this.baseURI): Observable<User> {
return Observable.create(observer => this.iteratePages(observer, uri));
}
private iteratePages(observer: Observer<User>, uri): void {
if (uri == null) { return observer.complete(); }
this.http.get(uri).subscribe(res => {
const data = res.json();
for (const user of data._embedded.users) {
observer.next(user as User);
}
const nextUri = (data._links && data._links.next) ? data._links.next.href : null;
this.iteratePages(observer, nextUri);
});
}