Try to get key values recursively from JSON in Angular 5 - json

I want to retrieve all the key values from a JSON file. For example in :
{
"total_count": 6,
"incomplete_results": false,
"items": [
{
"url": "https://api.github.com/repos/Samhot/GenIHM/issues/6",
"id": 293237635,
"number": 6,
"title": "Rechercher des documents",
"user": {
"login": "Samhot",
"id": 7148311
]
}
I would like to get :
["total_count", "incomplete_results", "items", "url", "url", "number", "title", "user", "login", "id"]
I have a function which return the content of my JSON in an observable :
getConfig(): Observable<any> {
return this.http.get<any>(this.myURL);
}
After that the data are reformated with .map to get only the keys with the Object.keys() function :
merge()
.pipe(
startWith({}),
switchMap(() => {
return this.getConfig();
}),
map(data => {
return Object.keys(data.items[0]);
}
)
)
.subscribe(data => {
this.dispo = data;
});
My problem is that i get only the keys that are in the level of the JSON I told
(data.items[0]) and not the ascendants or the descendants.
Of course I can create multiple requests but it asks to know in advance the structure of the JSON, what I want is to make it generic ...
How can I do to have an array with with all of my keys regardless of the structure of the JSON ?
Thanks in advance !

You would need to do a recursive function like:
function getDeepKeys(obj) {
const keys = Object.keys(obj);
const childKeys = keys
.map(key => obj[key])
.map(
value =>
Array.isArray(value)
? getDeepKeys(value[0])
: typeof value === "object"
? getDeepKeys(value)
: []
)
.reduce((acc, keys) => [...acc, ...keys], []);
return [...keys, ...childKeys];
}
const obj = {
total_count: 6,
incomplete_results: false,
items: [
{
url: "https://api.github.com/repos/Samhot/GenIHM/issues/6",
id: 293237635,
number: 6,
title: "Rechercher des documents",
user: {
login: "Samhot",
id: 7148311
}
},
{
url: "https://api.github.com/repos/Samhot/GenIHM/issues/6",
id: 293237635,
number: 6,
title: "Rechercher des documents",
user: {
login: "Samhot",
id: 7148311
}
}
]
};
console.log(getDeepKeys(obj));
Which then you would use like map(getDeepKeys). Note that this function assumes all the items in your array have the same schema.

Related

directline connection role and name not getting in BOT conversationUpdate

//For reference below - DirectLine Connection code
```(async function() {
window.WebChat.renderWebChat({
directLine: window.WebChat.createDirectLine({
secret: “My KEY”}),
userID : "myid",
username: "myName"
},
document.getElementById('chat_converse')
);
document.querySelector('#chat_converse > *').focus();
})().catch(err => console.error(err));```
//Once Connected. We will have below objects in BOT.
```{
"type": "conversationUpdate",
"id": "ERqgImAulq3",
"timestamp": "2020-06-18T07:07:03.448Z",
"serviceUrl": "https://directline.botframework.com/",
"channelId": "directline",
"from": {
"id": "AicCk0YN2Ap9n2Ev1ovbuc-k"
},
"conversation": {
"id": "AicCk0YN2Ap9n2Ev1ovbuc-k"
},
"recipient": {
"id": "BotName#xp113vQdWDM",
"name": "BotName"
},
"membersAdded": [
{
"id": "BotName#xp113vQdWDM",
"name": "BotName"
}
]
}```
//From - section we should get id, name, role. In the "from" object name and role key is missing //and id is present but with auto generated id not actual user id myid.
You're not getting a ConversationUpdate for the user, just the bot. You need to send a ConversationUpdate manually:
const store = window.WebChat.createStore({}, ({ dispatch }) => next => action => {
if (action.type === 'DIRECT_LINE/CONNECT_FULFILLED') {
dispatch({
type: 'WEB_CHAT/SEND_EVENT',
payload: {
name: 'webchat/join',
value: { language: window.navigator.language }
}
});
}
return next(action);
});
I have applied as below in my code, It helps. May be useful for others
const store = window.WebChat.createStore({}, ({ dispatch }) => next => action => {
if (action.type === 'DIRECT_LINE/CONNECT_FULFILLED') {
dispatch({
type: 'WEB_CHAT/SEND_EVENT',
payload: {
name: 'webchat/join',
value: { language: window.navigator.language }
}
});
}
return next(action);
});
window.WebChat.renderWebChat({
directLine: window.WebChat.createDirectLine({
secret: 'YourKey'
}),
userID : "UserID",
username: "UserName",
store
},
document.getElementById('chat_converse')
);
document.querySelector('#chat_converse > *').focus();
})().catch(err => console.error(err));
It will trigger two time bot activity, One without user info, One with user info. So I did checked at bot side if user info contains name kay then load my initial dialog something like below..It got worked for me. Thanks #mdrichardson
if (membersAdded[cnt].id === context.activity.recipient.id && context.activity.from && context.activity.from.name
&& context.activity.channelId=='directline') {
await dialog.run(context, conversationState.createProperty('DialogState'));
}

Angular Typescript access specific JSON object by id in an observable

I have this json string below and I want to either pull the "stocks" data array or the "contacts" data array based on whichever one I need for a given request:
[{
"id": "stocks",
"name": "Stocks",
"data": [
{
"id": 1,
"name": "Actuant Corporation",
"symbol": "ATU"
},
{
"id": 2,
"name": "Xilinx, Inc.",
"symbol": "XLNX"
}
]
},
{
"id": "contacts",
"name": "Contacts",
"data": [
{
"id": 1,
"full_name": "Betty Traise"
},
{
"id": 2,
"full_name": "Hank Hurrion"
},
{
"id": 3,
"full_name": "Calvin Ommanney"
}
]
}]
For example, in the function below, which is an observable, assume the payload argument is "contacts". In that case, I need to return the "id: "contacts" data array. Here's the code I'm using:
loadData$(payload: any = {}): Observable<any> {
// paths: {
// titlemaps: 'http://localhost:4100/data'
// },
// return this.service.get(this.config.paths.titlemaps, payload);
const JSON: any = this.service.get(this.config.paths.titlemaps, payload);
console.log('payload: ' + payload, 'json: ' + JSON); // if payload is "contacts", return only the contacts
return JSON.find(data => data.id === 'contacts');
}
The console log returns "contacts" and the entire JSON as expected. However, the JSON.find fails with error:
ERROR TypeError: JSON.find is not a function
When I switch the function types a bit, I get typescript compiler error:
[ts] Property 'find' does not exist on type 'Observable'.
What am I missing?
The result of your service call seems to be an observable, you can transform the result and return a new value with rxjs pipeable operators:
import { map } from 'rxjs/operators';
....
loadData$(payload: any = {}): Observable<any> {
return this.service.get(this.config.paths.titlemaps)
.pipe(
map(result => result.find(data => data.id === payload))
);
}
Hope it helps!
I moved the mapping/find operation to the service since you're passing those as params but you don't have to do it like that of course...
https://stackblitz.com/edit/angular-2lajx4
The gist...
get(url, payload) {
return of(results)
.pipe(map((res: any) => {
return res.find(data => data.id === payload)
}));
}
Just using of() here to simulate an observable, results is the JSON you provided above...
loadData$ subs to the get and puts the data into a variable for consumption
data: any;
loadData$(payload: any = {}) {
this.service.get('../results.json', payload).subscribe(data => {
this.data = data
console.log('payload: ' + payload, 'json: ' + this.data); // if payload is "contacts", return only the contacts
});
}

Can't get certain data from JSON, returns undefined Angular 6

I'm trying to extract "data" from this JSON but it keeps throwing undefined as result.
Extract of code where I'm getting this error:
ngOnInit(): void {
this.testService.getTestWithObservable().subscribe(
res => {
let user = res["users"];
let user_data = user["data"];
this.user_data = user_data;
console.log(user_data);
console.log(res);
}
);
}
res outputs the whole JSON but user_data throws:
ERROR TypeError: Cannot read property 'data' of undefined
at SafeSubscriber._next
JSON
[{
"id": 1,
"users": {
"user_id": 14,
"data": [{
"name": "James",
"age": 20
},
{
"name": "Damien",
"age": 25
}]
}
}
{
"id": 2,
"users": {
"user_id": 11,
"data": [{
"name": "James",
"age": 20
},
{
"name": "Damien",
"age": 25
}]
}
}]
Your JSON is an array so you need to use an index or a loop to access one of your item like this:
ngOnInit(): void {
this.testService.getTestWithObservable()
.subscribe(
res => res.forEach(user => this.user_data = [...(this.user_data || []), user['users']['data']]);
);
}
Or:
ngOnInit(): void {
this.testService.getTestWithObservable()
.subscribe(
res => this.user_data = res[0]['users']['data']);
);
}
The first code will store in the user_data array all the data prop of each users
The result is array so you have to use index to access to the array data ,
this.testService.getTestWithObservable()
.map( result => result.map( i => i.users.data) ) // array of data array
.subscribe(
res => {
this.user_data = [];
res.forEach(i => this.user_data(...i));
console.log(this.user_data); // all users data as array
}
);
}
loop throw the data by ngFor
<div *ngFor="let user of user_data">
{{user.name}} , age : {{user.age}}
</div>

Angular2, get data from REST call

I'm triyng to get data from json file by a id, by I'm getting all the content.
Here the JSON:
[
{ "id": "1", "name": "Carlos", "apellidos":"López", "edad":"30", "ciudad":"Hospitalet" },
{ "id": "2", "name": "Arantxa", "apellidos":"Pavia", "edad":"24", "ciudad":"Barcelona" },
{ "id": "3", "name": "Didac" , "apellidos":"Pedra", "edad":"muchos", "ciudad":"Cornellà" },
{ "id": "4", "name": "Daniel" , "apellidos":"Farnos", "edad":"nolose", "ciudad":"Barcelona" }
]
Service:
private usersUrl = 'app/users.json';
getUser(id: String): Observable<User>{
let body = JSON.stringify(
{
"token": "test",
"content": {
"id": id
}
}
);
let headers = new Headers({ 'Content-Type': 'application/json' });
let options = new RequestOptions({
headers: headers,
body : body
});
return this.http.get(this.usersUrl, options)
.map(res => res.json()).catch(this.handleError);
}
Angular Component:
ngOnInit(){
this.route.params.subscribe(params => {
let id = +params['id'];
this.apiService.getUser(id).subscribe( (res) => { console.log(res); } );
})
}
Console.log:
Array[4]0: Object1: Object2: Object3: Objectlength: 4__proto__: Array[0]
Is the JSON bad?
Thanks.
Because you didn't filter the result by id.
.map(res => res.json())
.map(x > x.find(x => x.id == id) // filter by selected id
.catch(this.handleError);

Getting json object data with react

I am attempting to pull data out of json like this, which is imported as "values"
{
"content": {
"person": [
{
"name": "Test"
"age" : "24:
}
]
}
}
I am using .map like below but getting the error .default.map is not a function I believe it is because i have objects not arrays, i've tried a bunch of stuff including object.keys but i'm getting errors all over the place, any direction would be appreciated.
import values from './sample.json'
const vals = values.map((myval, index) => {
const items = person.items.map((item, i) => {
return (
<div>{item.name}</div>
)
})
return (
<div>{items}</div>
)
})
I think your data and code have some errors. But after fixing those and also changing the name from 'person' to 'people' if that's what you are after, here's the code that does what you are trying to do:
var data = {
content: {
people: [
{
name: "Test",
age: 24,
},
{
name: "Foo",
age: 25,
},
],
},
};
var App = React.createClass({
render: function () {
var people = data.content.people.map(function (person) {
return <div>{person.name}</div>;
});
return <div>{people}</div>;
},
});
ReactDOM.render(<App />, document.getElementById("app"));
And here's the JSBin for that: https://jsbin.com/coyalec/2/edit?html,js,output
Update: I'm updating the answer with more detailed example. It now deals with data more generically, like it doesn't assume what are the entries of 'contents' and such, but it knows that each type like 'people' or 'pets' are an array.
var data = {
content: {
people: [
{
name: "Test",
age: 24,
},
{
name: "Foo",
age: 25,
},
],
pets: [
{
name: "Sweety",
age: 3,
},
{
name: "Kitty",
age: 5,
},
],
},
};
var App = React.createClass({
render: function () {
// Get the keys in data.content. This will return ['people', 'pets']
var contentKeys = Object.keys(data.content);
// Now start iterating through these keys and use those keys to
// retrieve the underlying arrays and then extract the name field
var allNames = contentKeys.map((t) =>
data.content[t].map((e) => <div>{e.name}</div>)
);
return <div>{allNames}</div>;
},
});
ReactDOM.render(<App />, document.getElementById("app"));
And here's the latest JSBin: https://jsbin.com/coyalec/4/edit?html,js,output