Can not import custom pipes in Angular 2 while Grouping data - json

I'm newbie to Angular JS.
I am using Angular 2 in my project.
My JSON data is in below
"locations": [
{
"id": "ASS",
"name": "test center",
"city": "Staten Island",
"zip": "10301",
"state" : "texas"
},
{
"id": "ASD",
"name": "test center1",
"city": "Staten Island",
"zip": "10301",
"state" : "Florida"
},
{
"id": "AAY",
"name": "test center2",
"city": "Staten Island",
"zip": "10301",
"state" : "Florida"
},
{
{
"id": "ASD",
"name": "test center1",
"city": "Staten Island",
"zip": "10301",
"state" : "Florida"
}
],
I want to display data group by state.
texas : <div>ASS</div>
florida : <div>ASD</div>
<div>AAY</div>
<div>ASD</div>
group.pipe.ts:
#Pipe({name: 'groupBy'})
export class GroupByPipe implements PipeTransform {
transform(value: Array<any>, field: string): Array<any> {
console.log('test');
const groupedObj = value.reduce((prev, cur)=> {
if(!prev[cur[field]]) {
prev[cur[field]] = [cur];
} else {
prev[cur[field]].push(cur);
}
return prev;
}, {});
return Object.keys(groupedObj).map(key => ({ key, value: groupedObj[key]
}));
}
location.component.ts:
import {GroupByPipe} from '../group.pipe';
#NgModule({
declarations : [GroupByPipe]
})
My error :
Unhandled Promise rejection: Template parse errors:
The pipe 'groupBy' could not be found (" <div class="col-sm-12 left_otr">
<div class="col-md-6 col-sm-6 left" *ngFor="let [ERROR ->]item
of pagedItems | groupBy : 'state'">
How to solve this?

Just Passed the array and field to the below code:
transform(value: Array<any>, field: string): Array<any> {
const groupedObj = value.reduce((prev, cur)=> {
if(!prev[cur[field]]) {
prev[cur[field]] = [cur];
} else {
prev[cur[field]].push(cur);
}
return prev;
}, {});
return Object.keys(groupedObj).map(key => ({ key, value: groupedObj[key] }));
}
didn't used pipes.
updated my html as like below:
<div *ngFor="let item1 of pagedItems">
<h1>{{item1.key}}</h1>
<div *ngFor="let item of item1.value">
// my logic is here.
</div

Related

Print all elements of fetched data array in react

Hey I am a beginner in react trying to make my first full stack app, I am fetching data from mongodb using axios and storing data in fetchedjobs array. Jobtitle array only has the title property of the fetchedjobs and I want to print all the entries but not able to. For now I am printing these elements by hard coding the indexes {this.state.jobtitle[0]} .
Please Help
class FindJob extends Component{
constructor(props){
super(props);
this.state={
fetchedjobs:[],
jobtitle:[],
}
}
componentDidMount(){
axios.get(' http://localhost:4002/api/findjob')
.then(res=>{
this.setState({
fetchedjobs:res.data
})
let jobtitle=[]
this.state.fetchedjobs.map(fetchedjob=>
jobtitle.push(fetchedjob.jobtitle)
)
console.log(jobtitle[0])
this.setState({
jobtitle
})
})
}
render(){
return(
<div className="content">
<h5>{this.state.jobtitle[0]}</h5>
</div>
);
}
}
export default FindJob;
fetched json
[
{
"_id": "600469700459a40c088f3dde",
"jobtitle": "swe",
"company": "ibm",
"officelocation": "ggn",
"jobtype": "Part Time",
"publisher": "sid",
"date": "2021-01-17T16:44:32.084Z",
"__v": 0
},
{
"_id": "600469aa0459a40c088f3ddf",
"jobtitle": "janitor",
"company": "cisco",
"officelocation": "delhi",
"jobtype": "Full Time",
"publisher": "tanmya",
"date": "2021-01-17T16:45:30.218Z",
"__v": 0
},
{
"_id": "60046ae8b95ae81c14278f9e",
"jobtitle": "fljdk",
"company": "ndkf",
"officelocation": "mdfkfm",
"jobtype": "Part Time",
"publisher": "tanmya",
"date": "2021-01-17T16:50:48.311Z",
"__v": 0
}
]
You can create sync call in setState method and try it,
axios.get(' http://localhost:4002/api/findjob')
.then(res=>{
this.setState({ fetchedjobs:res.data }, () => {
let jobtitle=[]
this.state.fetchedjobs.map(fetchedjob=>
jobtitle.push(fetchedjob.jobtitle)
)
this.setState({ jobtitle})
})
})
Try this:
render(){
return(
<div className="content">
{this.state.jobtitle.length?this.state.jobtitle.map((item)=>{
return <h5>{item._id}</h5> //here you can display any property that you wish to
})
:null}
</div>
);
}

How to extract only certain properties of json, returning as an observable using rxjs

For example this is the json which I am receiving,
{
"events": [...
],
"total": 12341,
"students": [
{
"id": 1,
"first_name": "John",
"last_name": "Apple"
},
{
"id": 2,
"first_name": "Bob",
"last_name": "Banana"
},
{
"id": 3,
"first_name": "Charles",
"last_name": "Carrot"
}
]
}
And I want to transform the data to the following form, and return it as an observable
[
{
"first_name": "John",
"last_name": "Apple"
},
{
"first_name": "Bob",
"last_name": "Banana"
},
{
"first_name": "Charles",
"last_name": "Carrot"
}
]
I have tried the following, but it returns undefined.
getStudentsName(): Observable<any> {
const requestUrl = this.rootURL + `students/`;
let studentsInfo = this.http.get<any>(requestUrl).pipe(map(o => o.students));
return studentsInfo.pipe(map(students => {students.first_name, students.last_name}));
}
returns undefined when subscribing to observable
this.getStudentsInfoService.getStudentsName()
.subscribe((result) => console.log('here', result));
It looks like it can't find students. Try this :
return studentsInfo.pipe(map(s => { return {
first_name: s.first_name,
last_name: s.last_name,
}}));
Your problem is, that students is an array, but you handle it as an object. You need to add a nested map: 1 for rxjs, 1 for the array
return studentsInfo.pipe(
map(studentsArray => studentsArray.map(student => ({
first_name: student.first_name,
last_name: student.last_name
}))),
);
PS.: Using types instead of any would have shown you that. Neither you nor the other responders saw this issue due to missing typing.
Here is a short code snippet.
const object = {
"total": 12341,
"students": [
{
"id": 1,
"first_name": "John",
"last_name": "Apple"
},
{
"id": 2,
"first_name": "Bob",
"last_name": "Banana"
},
{
"id": 3,
"first_name": "Charles",
"last_name": "Carrot"
}
]
}
let arr: any = [];
object.students.forEach(person => arr.push(
{
"first_name": person.first_name,
"last_name": person.last_name
}))
console.log(arr)
[LOG]: [{ "first_name": "John", "last_name": "Apple" },
{ "first_name": "Bob", "last_name": "Banana" }, { "first_name": "Charles", "last_name": "Carrot" }]
You can iterate over students with a foreach loop and then create a new json which you then push in your new array
this.http.get<any>(requestUrl).pipe(map(o => o.students.foreach(person => arr.push({
...}));
The Problem
The Problem is with your how you return your observable
Lets break the code down
let studentsInfo = this.http.get<any>(requestUrl).pipe(map(o => o.students));
In the above studentsInfo will be of type Observable<any>
Next line is as per below
return studentsInfo.pipe(
map(students => {
students.first_name, students.last_name
}
));
Lets have a look at the below section
{
students.first_name, students.last_name
}
This part of the section actually has no return statement hence by default javascript returns undefined!
Solution
To use arrow function without a return statement, you will need to wrap {} inside a () like below
students => ({ })
Below will work
getStudentsName(): Observable<any> {
return this.http.get<any[]>(`${this.routeURL}/students`).pipe(
map(o => o.students));
}

How can I fetch a particular data from nested array from JSON file in Angular by using params?

This is my JSON file.
{mood:
[ {
"id":"1",
"text": "Annoyed",
"cols": 1,
"rows": 2,
"color": "lightgreen",
"route":"/angry",
"musics": [
{
"id": "0",
"name": "English- Heaven's Peace",
"image": "images/music.png",
"link": "https://www.youtube.com/playlist?list=PLPfXrbtn3EgleopO8DiEdsNKgqYZZSEKF",
"descpription": "Tunes that soothe your pained soul",
"reviews": [
{
"name": "abc",
"rating": 4,
"review": "energetic",
"date": ""
}
]
},
{
"id": "1",
"name": "English- Hell's Fire",
"image": "images/music.png",
"link": "https://www.youtube.com/playlist?list=PLPfXrbtn3EgmZitRQf1X1iYwWW_nUF44L",
"descpription": "Beats that match the ones of your heart",
"reviews": [
{
"name": "abc",
"rating": 3.5,
"review": "energetic",
"date": ""
}
]
},
{
"id": "2",
"name": "Hindi",
"image": "images/music.png",
"link": "",
"descpription": "",
"reviews": [
{
"name": "abc",
"rating": 4,
"review": "energetic",
"date": ""
}
]
},
{
"id": "3",
"name": "Punjabi",
"image": "images/music.png",
"link": "https://www.youtube.com/playlist?list=PLPfXrbtn3Egnntch2thUO55YqPQgo4Qh7",
"descpription": "",
"reviews": [
{
"name": "abc",
"rating": 4,
"review": "energetic",
"date": ""
}
]
},
{
"id": "4",
"name": "Mix and Match",
"image": "images/music.png",
"link": "https://www.youtube.com/playlist?list=PLPfXrbtn3EglN5LVTETqH3ipRLfXmY6MB",
"descpription": "",
"reviews": [
{
"name": "abc",
"rating": 5,
"review": "energetic",
"date": ""
}
]
}
]
} ]
}
I have created angular services in a file name mood.services.ts
import { Injectable } from '#angular/core';
import { Mood } from '../shared/mood';
import { Observable, of } from 'rxjs';
import { delay } from 'rxjs/operators';
import { map, catchError } from 'rxjs/operators';
import { HttpClient, HttpHeaders } from '#angular/common/http';
import { baseURL } from '../shared/baseurl';
import { ProcessHTTPMsgService } from './process-httpmsg.service';
#Injectable({
providedIn: 'root'
})
export class MoodService {
constructor(private http: HttpClient,
private processHTTPMsgService: ProcessHTTPMsgService) { }
getMoods(): Observable<Mood[]> {
return this.http.get<Mood[]>(baseURL + 'moods')
.pipe(catchError(this.processHTTPMsgService.handleError));
}
getMood(id: number): Observable<Mood> {
return this.http.get<Mood>(baseURL+'moods/'+id)
.pipe(catchError(this.processHTTPMsgService.handleError));
}
getMoodIds(): Observable<number[] | any> {
return this.getMoods().pipe(map(moods => moods.map(mood => mood.id)))
.pipe(catchError(error => error));
}
getMusicIds(): Observable<number[] | any> {
return this.getMoods().pipe(map(musics => musics.map(music => music.id)))
}
}
And this is my musicdetail.component.ts file which will fetch the data of the particular music that is chosen.
import { Component, OnInit, Inject } from '#angular/core';
import { Mood } from '../shared/mood';
import { Music } from '../shared/music';
import { Review } from '../shared/review';
import { MoodService } from '../services/mood.service';
import { Params, ActivatedRoute } from '#angular/router';
import { Location } from '#angular/common';
import { switchMap } from 'rxjs/operators';
#Component({
selector: 'app-musicdetail',
templateUrl: './musicdetail.component.html',
styleUrls: ['./musicdetail.component.scss']
})
export class MusicdetailComponent implements OnInit {
mood : Mood;
music: Music;
musicIds: string;
errMess: string;
prev : string;
next : string;
review: Review;
constructor(private moodservice: MoodService,
private route: ActivatedRoute,
private location: Location,
#Inject('BaseURL') private BaseURL) { }
ngOnInit(): void {
this.route.params.pipe(switchMap((params: Params) => {return this.moodservice.getMood(params['id']);
}))
.subscribe(mood => {this.mood = mood;}, errmess => this.errMess = <any>errmess);
}
}
I have passed both mood.id and music.id when clicked in music.component.ts using '[routerLink]="['/musicdetails', mood.id, music.id]"`, on the list of music but I am unable to make logic to fetch particular music to display all its details. I am able to get mood-id using getMood(id) service but unable to do the same for music inside that mood.
WARNING:
your JSON data is wrong, Either you have missing single quote or double quote or 2nd bracket or third bracket. I don't know what you missed, its a long JSON file .
There is a JSON fixing website ( this one ) . I pasted your JSON and fixed it first.
Now I am writing this answer using correct version of your JSON (you can see it below)
So here it the answer:
The answer is simple - just use filter method to filter a particular property you need
.ts :
let jsonData =
{
"mood":[
{
"id":"1",
"text":"Annoyed",
"cols":1,
"rows":2,
"color":"lightgreen",
"route":"/angry",
"musics":[
{
"id":"0",
"name":"English- Heaven's Peace",
"image":"images/music.png",
"link":"https://www.youtube.com/playlist?list=PLPfXrbtn3EgleopO8DiEdsNKgqYZZSEKF",
"descpription":"Tunes that soothe your pained soul",
"reviews":[
{
"name":"abc",
"rating":4,
"review":"energetic",
"date":""
}
]
},
{
"id":"1",
"name":"English- Hell's Fire",
"image":"images/music.png",
"link":"https://www.youtube.com/playlist?list=PLPfXrbtn3EgmZitRQf1X1iYwWW_nUF44L",
"descpription":"Beats that match the ones of your heart",
"reviews":[
{
"name":"abc",
"rating":3.5,
"review":"energetic",
"date":""
}
]
},
{
"id":"2",
"name":"Hindi",
"image":"images/music.png",
"link":"",
"descpription":"",
"reviews":[
{
"name":"abc",
"rating":4,
"review":"energetic",
"date":""
}
]
},
{
"id":"3",
"name":"Punjabi",
"image":"images/music.png",
"link":"https://www.youtube.com/playlist?list=PLPfXrbtn3Egnntch2thUO55YqPQgo4Qh7",
"descpription":"",
"reviews":[
{
"name":"abc",
"rating":4,
"review":"energetic",
"date":""
}
]
},
{
"id":"4",
"name":"Mix and Match",
"image":"images/music.png",
"link":"https://www.youtube.com/playlist?list=PLPfXrbtn3EglN5LVTETqH3ipRLfXmY6MB",
"descpription":"",
"reviews":[
{
"name":"abc",
"rating":5,
"review":"energetic",
"date":""
}
]
}
]
}
]
} ;
// music - i can save here
let r = jsonData.mood[0].musics.filter(data => data.id == "2");
// music - or i can console.log it also
// i am comparing with 2 here - compare with your id number
// according to your need
console.log(jsonData.mood[0].musics.filter(data => data.id == "2"));
// in the same way you can search mood also
console.log(jsonData.mood.filter(data=> data.id == "1"));
to get something from parameter of url : follow this
there are multiple ways to get params from url
see this question : stackoverflow
see this blog : digitalocean

issues with fetching Json in react

I apologise as this is probably either very basic or i've done something compeltely wrong. I'm brand new to React, and coding in general, and I'm trying to make a React app that shows the recipes im using on cards. The cards in turn should be searchable and dynamic, dissapearing if they don't match etc.
This is my app.js file, that when run, it just brings up my custom "Loading" screen without data. Where have I messed up on this?
import React, {Component} from 'react';
import CardList from './CardList';
import SearchBox from './SearchBox';
import Scroll from "./Scroll";
import "./App.css"
class App extends Component {
constructor() {
super()
this.state = {
recipes: [],
searchfield: "",
}
}
componentDidMount() {
fetch("./recipedata.json")
.then(response => { return response.json();})
.then(recipedata => {this.setState({recipes: recipedata})});
}
onSearchChange= (event) =>{
this.setState({searchfield: event.target.value})
}
render() {
const filteredRecipe = this.state.recipes.filter(recipes =>{
return recipes.name.toLowerCase().includes(this.state.searchfield.toLowerCase());
})
if (this.state.recipes.length === 0) {
return <h1 class="f1 tc">Loading</h1>
} else {
return(
<div className="tc">
<h1 className="f1">Recipes</h1>
<SearchBox searchChange={this.onSearchChange} />
<Scroll>
<CardList recipe={filteredRecipe}/>
</Scroll>
</div>
)
}
}
}
export default App
Thanks in advance
edit: I have been asked to post the contents of recipedata.json:
[
{
"id" : 1,
"name" : "Carrot cake",
"type" : "sweet",
"author" : "Grandma",
"link" : "recipes/carrotcake.html"
},
{
"id" : 2,
"name" : "Spicy chicken pitta filling",
"type" : "savoury",
"author" : "Grandma",
"link" : "recipes/chickenpitta.html"
},
{
"id" : 3,
"name" : "Mushroom ham and chicken crusty puff pies",
"type" : "savoury",
"author" : "Grandma",
"link" : "recipes/crustypuff.html"
},
{
"id" : 4,
"name" : "Sweet potato pumpkin seed rolls",
"type" : "savoury",
"author" : "Grandma",
"link" : "recipes/sweetpotrolls.html"
},
{
"id": 5,
"name": "Wild mushroom wafer",
"type": "savoury",
"author" : "Grandma",
"link": "recipes/mushroomwafer.html"
},
{
"id": 6,
"name": "Piri Piri chicken sauce",
"type": "savoury",
"author": "Grandma",
"link": "recipes/piriRecipe.html"
},
{
"id": 7,
"name": "Chicken Liver Pate'",
"type": "savoury",
"author": "Grandma",
"link": "recipes/pate.html"
},
{
"id": 8,
"name": "Creamy mushroom pasta",
"type": "savoury",
"author": "Grandma",
"link": "recipes/mushroompasta.html"
},
{
"id": 9,
"name": "Cheesey garlic bread",
"type": "savoury",
"author": "Grandma",
"link": "recipes/gbread.html"
},
{
"id": 10,
"name": "Mini quiches",
"type": "savoury",
"author": "Grandma",
"link": "recipes/miniquiche.html"
},
{
"id": 11,
"name": "Sticky lemon ginger cake",
"type": "sweet",
"author": "Grandma",
"link": "recipes/stickyrecipe.html"
},
{
"id": 12,
"name": "Sticky toffee pudding",
"type": "sweet",
"author": "Grandma",
"link": "recipes/stickytoffee.html"
},
{
"id": 12,
"name": "Iced cream buns",
"type": "sweet",
"author": "Grandma",
"link": "recipes/icedcreambuns.html"
},
{
"id": 13,
"name": "Pineapple Cake",
"type": "sweet",
"author": "Grandma",
"link": "recipes/pineapplecake.html"
}
]
Edit 2:
Thanks for your help all, I've now fixed the app.js file and the Json is being returned. I'm now faced with this error in my CardList.js component:
TypeError: Cannot read property 'map' of undefined
CardList
C:/Users/mattj/OneDrive/Desktop/coding/gmcb-react-app/src/CardList.js:5
2 | import Card from './Card.js';
3 |
4 | const CardList = ({recipes}) => {
> 5 | return <div>
6 | {recipes.map((recipedata, i) => {
7 | return(
8 | <Card
code:
import React from 'react';
import Card from './Card.js';
const CardList = ({recipes}) => {
return <div>
{recipes.map((recipedata, i) => {
return(
<Card
key={i}
id={recipes[i].id}
name={recipes[i].name} />
)
})}
</div>
}
export default CardList
What have I messed up here?
Regarding issue #2 you posted it is really tough to say, however I think you are overcomplicating things with your card list. You should simply pass an array of filtered recipes to your component.
Your card list component you should just pass an entire recipe option to the component instead of trying to pass specific props. If in the future you add more keys to each recipe object you wont have to adjust your card list
const CardList = ({recipes}) => {
return (
<div>
{
recipes.map(recipe => {
return <Card recipe={recipe} key={recipe.id} />
})
}
</div>
)
}
Inside your card component you can destructure the keys off the recipe object
const Card = ({recipe}) => {
return (
<div>
<h3>{recipe.name}</h3>
<p>{recipe.type} - {recipe.author}</p>
<hr />
</div>
)
}
I made you a code sandbox, I used React Hooks and a mockAxios call in order to fake what a server would do and so you have some code for if you want to call an API in the future.
https://codesandbox.io/s/broken-glitter-4wb61?file=/src/App.js
You don't need to use fetch to get the data from the local json file.
You can simply import the contents of ./recipedata.json by doing this:
import recipedata from './recipedata.json';
And then change your componentDidMount to this:
componentDidMount() {
this.setState({ recipes: recipedata });
}
You mostly use fetch when you are trying to fetch data from a http server. Read more here and here
To support #Qubaish Bhatti's comment, yes, there is no need to have recipes in state. You can use it directly and do away with this.state.recipes

Json to Angular object

I have following JSON and I try to map it to Angular 7 object with no result:
[
{
"id": "123456",
"general": {
"number": "123",
"name": "my name 1",
"description": "My description with <li> html tags </li>"
},
"option1": {
"name": "option1 name"
},
"option2": {
"suboption2": {
"name": "suboption2 name"
}
}
},
{
"id": "789123",
"general": {
"number": "456",
"name": "my name 2",
"description": "My description with <li> html tags </li>"
},
"option1": {
"name": "option2 name"
},
"option2": {
"suboption2": {
"description": "My description with <li> html tags </li>"
}
}
}
]
I tried to create MyClass instance with fields with the same name as in the JSON file and cast that JSON file to this class but with no success.
I would create a mapper (service) that receives your DTOs (data transfer object, essentially your JSON response) as parameter and output your MyClass object.
In your map function (in your service), you would iterate over your array of DTOs and create a new instance of MyClass for each DTO and then return your array of MyClass
map(myClassDtos:MyClassDTO[]):MyClass[]{
return myClassDtos.map(dto=>{
return new MyClass(...);
});
}
First I would change your JSON structure for something like this, it's more structured:
[
{
"id": "123456",
"general": {
"number": "123",
"name": "my name 1",
"description": "My description with <li> html tags </li>"
},
"options": [
{
"name": "option1 name"
},
{
"name": "option2 name",
"suboptions": [
{
"name": "suboption1 name"
}
]
}
]
},
{
"id": "789123",
"general": {
"number": "456",
"name": "my name 2",
"description": "My description with <li> html tags </li>"
},
"options": [
{
"name": "option1 name"
},
{
"name": "option2 name",
"suboptions": [
{
"name": "suboption1 name"
},
{
"name": "suboption2 name"
}
]
},
{
"name": "option3 name",
"suboptions": [
{
"name": "suboption1 name"
},
{
"name": "suboption2 name"
}
]
}
]
}
]
After that write model interfaces to model all your JSON array items:
main-element.ts
import { General } from './general';
import { Options } from './options';
export interface Element {
id?: number;
general?: General;
options?: Options[];
}
generl.ts
export interface General {
number?: number;
name?: string;
description?: number;
}
import { Suboptions } from './suboptions';
options.ts
export interface Options {
name?: string;
suboptions?: Suboptions[];
}
suboptions.ts
export interface Suboptions {
name?: string;
}
And finally, where you want to map, simply do this:
import { Component } from '#angular/core';
import { Element } from './models/main-element';
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
private elementsList: Element[] = [];
constructor(){
}
mapJSON(){
this.elementsList = this.someJsonString; //Here you need to insert your json string data
console.log(this.elementsList);
}
}
As result you will get this, if you print in console the elementsList object that's defined on the last part of code.