print attributes values from JSON array in Angular2 - arrays

I'm using Angular2 and I have retrieved some data from Firebase in this way:
dataset: any;
onGetData() {
this._dataService.getAllData()
.subscribe(
data => this.dataset = JSON.stringify(data),
error => console.error(error)
);
if I print dataset I get this JSON:
{"-KE8XuCI7Vsm1jKDJIGK":{"content":"aaa","title":"bbb"},"-KE8XvM268lWhXWKg6Rx":{"content":"cccc","title":"dddd"}}
How can I print out a list made up of only the title values from this JSON array?
I'd like to have: bbb - dddd

You can only iterate over an array using ngFor. In your case you need to implement a custom pipe to iterate over keys of an object.
Something like that:
#Pipe({name: 'keyValues'})
export class KeysPipe implements PipeTransform {
transform(value, args:string[]) : any {
let keys = [];
for (let key in value) {
keys.push({key: key, value: value[key]);
}
return keys;
}
}
and use it like that:
<span *ngFor="#entry of dataset | keyValues">
Title: {{entry.value.title}}
</span>
See this question for more details:
How to display json object using *ngFor

In your view you need
<div *ngFor='#data of dataset'>
{{ data.title }} -
</div>

Related

Search function from JSON structure

I am looking for a solution to search JSON values based on the user input in the search field.
For example: if the user keys in ASD, any data that contain ASD in the Json values should display.
I found an example which works like how i wanted it to be. However, they are not using JSON structure.
Here's the code that I have followed:
App.svelte:
<script>
import Search from "./Search.svelte";
const data = [
"Metrics Server",
"Node.js",
"Virtual Machine",
"Virtual Private Server",
];
</script>
<Search autofocus {data} let:filtered>
<ul>
{#each filtered as item}
<li>{item}</li>
{/each}
</ul>
</Search>
Search.svelte
<script>
import {onMount} from "svelte";
export let autofocus = false;
export let data = [];
let input = undefined;
let value ="";
onMount(() =>{
if(autofocus) {
input.focus();
}
});
$: filtered = data.filter((item) =>
item.toLowerCase().includes(value.toLowerCase()));
</script>
<style>
ul{
list-style:none;
}
</style>
<input bind:this="{input}" type="search" bind:value />
<ul>
{#each filtered as item}
<li>{item}</li>
{/each}
</ul>
This code does not work for JSON structure such as:
{"name": "tommy, "class":"a"},
{"name": "dummy, "class":"b"} ...
It will return an error like:
item.toLowerCase is not a function
How do I implement a search function that will return me the name if the user search for "tommy"
This is how i am retrieving the Json data:
let info ="";
onMount(async () =>{
const resp = await fetch('https:xx.xxx.xxx')
info = await resp.json();
});
And the data I am getting back is in this format: [editted]
[ {
"table_schema": "x",
"table_name": "a",
"column_name": "typname",
"data_type": "name",
"character_maximum_length": null
},
{
"table_schema": "b",
"table_name": "x",
"column_name": "typnamespace",
"data_type": "oid",
"character_maximum_length": null
}]
I have edited my real JSON file. The code does works for my dummy JSON but not the real one. Any idea?
You would have to loop through each of the properties on your items and compare each of them:
first loop over the items with data.filter
get all the props of each item Object.keys(item)
check if at least one matches a condition .some
compare the key in the item to the value item[key].toLower....
$: filtered = data.filter(item =>
Object.keys(item).some(key =>
item[key].toLowerCase().includes(value.toLowerCase())
)
);
Note that this code assumes all items in your array are objects, it will fail if you have a mix between objects and strings:
[ "Tommy", { name: "Sammy" }]
Here the first element doesn't really have 'keys'. You would have to add an additional check for that first.

mapping from rest response

I am working in an example with the Dog Api (https://dog.ceo/api/breeds/list/all), the response for the breeds endpoint is something like that:
{
"message": {
"affenpinscher": [],
"african": [],
"airedale": [],
"akita": [],
"appenzeller": [],
"australian": ["shepherd"]
}
I need that my breed service, returns an observable of Breed
export class Breed {
name : String;
subbreeds : String[]
}
This call is returning an object with the property message. How I can map in my service for return an Observable<Breed[]> from that API Rest response.
getAll() : Observable<Breed[]> {
return this.http.get<Breed[]>("https://dog.ceo/api/breeds/list/all");
}
Actually this question is nothing about rxjs and angular 8, it about JavaScript.
export class Breed {
// public modifier is a short hand for this.name = name
constructor(public name: string, public subbreeds: string[]) {}
}
class Service {
getAll() {
return this.http
.get<Breed[]>('https://dog.ceo/api/breeds/list/all')
.pipe(
map(data => // map here is a rxjs operator, do not confuse with JS array's map
// Object.entries is convert Object's key value to entries [key, value] array
Object.entries(data.message).map( // JS array map method mapping each entry to Breed instance
// destructing from entry and return a Breed instance
([breed, subbreed]) => new Breed(breed, subbreed)
),
),
);
}
}
If you not sure about any term or method, please check MDN and RxJS official document

Group by Data Field

I have a list component contains SUBJECT, NO, DESCRIPTION fields. For example: ACC 121, descr.., ACC 121 descr..., ACC 122 descr... ACC 211 desc.... How do I group by the same SUBJECT and NO in tag and DESCRIPTION in sub components?
Courses=[{id:1, SUBJECT: ACC, NO:121,DESCR: 'class description1'},
{id:2, SUBJECT:ACC, NO:121, DESCR:'class description2'},
...]
const CourseList=({Courses, onCourseSelect})=>{
const renderedList= Courses.map(course=>{
return (
//add <h2>{course.SUBJECT} {course.NO} ???
<CourseItem key={course.ID} descr={course.DESCR} onCourseSelect={onCourseSelect} ></CourseItem>
);
})
return <div className="List ui relaxed divided list">
{renderedList}</div>
}
-----EDITED CODE
var _ = require('lodash');
const CourseList=({Courses, onCourseSelect})=>{
let renderedList = _.groupBy(Courses, 'SUBJECT','NO');
console.log(renderedList);
object list like below:
ACC: (26) […]
0: Object { ID: 1079, DESCR: "class description1", … }
1: Object { ID: 1080, DESCR: "class description2", … }
2: Object { ID: 1081, DESCR: "class description3",...}
​​
How to render each object? I tried:
return <div>
{Object.keys(renderedList).map(key => (
{renderedList["SUBJECT"]}
</div>
but it does not work. Thanks.
The Idea is to do something like this. Create a helper function to restructure the data into a multidimensional array by grouping them so that each array in the multidimensional array holds records about courses with the same id. then loop through the multidimensional array and perform whatever logic you want to.
let courses=[{id:1, SUBJECT: "ACC", NO:121,DESCR: 'class description1'},
{id:2, SUBJECT:"ACC", NO:121, DESCR:'class description2'},
...]
//Where ever we want to print the first group we just need to call the CourseList with a single input from the multidimentional structured array asonst
CourseList=(courses, onCourseSelect)=>{
//create another variable to hold the structured data
//this ensures that each key in the array is it self another array holding all the courses with that same id.
let structuredData = new Array();
courses.map(course => structuredData[course.id] = (courses.filter(co =>(co.id == course.id ))))
<div className="List ui relaxed divided list">
structuredData.map((data, k) => {
//each iteration over data is printing for a single group
console.log("Group", k)
data.map(course=>
<CourseItem key={course.id} descr={course.DESCR} onCourseSelect={onCourseSelect} />
)
})
</div>
}

Reading JSON into arrays in Angular (HttpClient)

i am trying to read JSON into different arrays using HttpClient for the use in Echarts, but since i am a newbie i couldn't find how to fill JSON into the different arrays.
the part code i used so far was:
....
label: Array<any>;
data: Array<any>;
tooltip: Array<any>;
constructor(private http: HttpClient) {
this.getJSON().subscribe(data => {
this.data=data.data;
this.label=data.label;
this.tooltip=data.tooltip;
console.log(data)
});
}
public getJSON(): Observable<any> {
return this.http.get("./assets/JSONData/TeamProgress.json")
}
the JSON file is formatted like this:
[{"label":"0","data":"0","tooltip":"0"},
{"label":"1","data":"-1","tooltip":" tooltip1"},
{"label":"2","data":"-1","tooltip":" tooltip2"},
...etc
i want to be able to get all labels of JSON in one array, and all data in another array, and all tooltips in a third array.
it would be great if you can help me.
thanks
First the result of that file should be a valid JSON structure aka (an object with key-values) you can group the array under a key called per example result
{
"result": [
{"label":"0","data":"0","tooltip":"0"},
{"label":"1","data":"-1","tooltip":" tooltip1"},
{"label":"2","data":"-1","tooltip":" tooltip2"},
//....Etc
]
}
Then you can access the data and filter it using map as below:
this.getJSON().subscribe((data:any) => {
this.label = data.result.map(element =>
// if you want to return an array of objects
{return {"label": element.label}}
// or if you want to return the raw values in an array, just do
element.label
});
this.data = data.result.map(element => {
return {"data": element.data}
});
this.tooltip = data.result.map(element => {
return {"tooltip": element.tooltip}
})
})

Angular2 access nested JSON

i´m new to Angular 2 in Typescript.I want to access D and G of my JSON with NgFor. Is there a way to access the elements?
[
{
"A":"B",
"C":{
"D": ["E","F"],
"G": ["H"]
}
}
]
I also createt a Plunker: Plunker
ngFor can't iterate over an object's keys out of the box. You must handle that yourself.
Pipes work well. Example: Updated Plunkr
#Pipe({name: 'keys'})
export class KeysPipe implements PipeTransform {
transform(value: any, args?: any[]): any[] {
let keys = Object.keys(value),
data = [];
keys.forEach(key => {
data.push(value[key]);
});
return data;
}
}

Resources