Reputation: 6383
This is my transactions API response:
[{
"id": 1,
"description": "Sandwich",
"date": "2017-09-01",
"category": "Take away",
"tags": ["Holidays"],
"amount": -2
},{
"id": 2,
"description": "Wage",
"date": "2017-08-31",
"category": "Wage",
"tags": [],
"amount": 2000
}]
I have the following code in my Angular service:
@Injectable()
export class TransactionsService {
private _transactionssurl = 'app/transactions/transactions.json';
constructor(private _http: Http){}
getTransactions(query = {}): Observable<ITransaction[]> {
return this._http.get(this._transactionssurl)
.map((response: Response) => <ITransaction[]> response.json())
.filter((value: any) => {
console.log(value)
if (query["month"] && transaction["month"].indexOf(query["month"]) === 0 ) return false;
if (query["category"] && transaction["category"] !== query["category"]) return false;
if (query["tag"] && transaction["tags"].includes(query["tag"])) return false;
return true;
})
.do(data => console.log(data))
.catch(this.handleError);
}
//...
}
You can see above that I'm trying to filter the data based on the passed in query object e.g. {month: "2017-09", tag: "Holidays"}
However, it seems that the function argument - transaction - which is passed into the filter function is the whole transactions array, not just a single transaction object which is how I expected it to be - how should I arrange the code to filter each individually? What should I be doing here instead? Most of the examples I've seen look somewhat like this so I tried to copy them.
Upvotes: 1
Views: 5628
Reputation: 29335
your observable stream that the operators act on is the ENTIRE response, which in this case is a list of data, not the elements in that list. You just need to act accordingly based on your desired outcome... if you want each item in the list to be transformed into items in an observable stream, so they go through operators one by one to the ultimate consumer then you do this:
getTransactions(query = {}): Observable<ITransaction[]> {
return this._http.get(this._transactionssurl)
.map((response: Response) => <ITransaction[]> response.json())
.flatMap(data => Observable.from(data))
.filter((value: any) => {
console.log(value)
if (query["month"] && transaction["month"].indexOf(query["month"]) === 0 ) return false;
if (query["category"] && transaction["category"] !== query["category"]) return false;
if (query["tag"] && transaction["tags"].includes(query["tag"])) return false;
return true;
})
.do(data => console.log(data))
.catch(this.handleError);
}
The flatMap -> from operation takes your list data and flattens it into an observable stream. But this doesn't make sense if you actually want the entire list at your final consumer in one observable stream item, as you would have to re aggregate the response with a reduce operator at the end like:
.reduce((acc, val) => acc.concat([val]), [])
If you just want to filter the list and pass it along, it's simple:
getTransactions(query = {}): Observable<ITransaction[]> {
return this._http.get(this._transactionssurl)
.map((response: Response) => <ITransaction[]> response.json())
.map((list: any) => {
return list.filter(value => {
if (query["month"] && transaction["month"].indexOf(query["month"]) === 0 ) return false;
if (query["category"] && transaction["category"] !== query["category"]) return false;
if (query["tag"] && transaction["tags"].includes(query["tag"])) return false;
return true;
});
})
.do(data => console.log(data))
.catch(this.handleError);
}
this just expects an array of data in the stream and runs the normal array filter method on it and maps it into the filtered list.
Upvotes: 2