Reputation: 1200
I am new to Typescript/Javascript and I am trying to get to the grips with the potential of rxjs. I use this code
return this.http.get<IXenoCantoResponse>(`${this.corsAnywhereUrl}${this.xenoCantoApiBaseUrl}${this.formatSearchTerm(searchTerm)}${this.recordingLength}`)
.pipe(
map(o => ({
numRecordings: o.numRecordings,
numSpecies: o.numSpecies,
page: o.page,
numPages: o.numPages,
recordings: o.recordings
}))
);
to map the response from a public API to an interface, IXenoCanto
:
export interface IXenoCantoResponse {
numRecordings: string;
numSpecies: string;
page: string;
numPages: string;
recordings: [];
}
It is actually the recordings[]
that I am interested in. In subsequent code, I use the fields in this array to construct an url and add it to yet another object:
data.forEach((element, index) => {
let sub = element.sono['full'].substr(0, this.getPosition(element.sono['full'], '\/', 6));
urls.push({
id: index + 1,
url: `${sub}${element['file-name']}`
});
});
export interface IVoice {
id: number;
url: string;
}
While it is true that this code does the job, I have been attempting to make it more effiently.
I wonder if it is possible to map the recordings any[]
response straight to a IVoice[]
in my initial map code. So I have tried changing the IXenoCantoResponse interface like so:
export interface IXenoCantoResponse {
numRecordings: string;
numSpecies: string;
page: string;
numPages: string;
recordings: IVoice[]
// recordings: [];
}
And then I can try to map the []
repsonse to the IVoice[]
directly, something like this:
return this.http.get<IXenoCantoResponse>(`${this.corsAnywhereUrl}${this.xenoCantoApiBaseUrl}${this.formatSearchTerm(searchTerm)}${this.recordingLength}`)
.pipe(
map(o => ({
numRecordings: o.numRecordings,
numSpecies: o.numSpecies,
page: o.page,
numPages: o.numPages,
recordings: o.recordings.map((element, index) => {
id: index + 1,
url: `${element.sono['full'].substr(0, this.getPosition(element.sono['full'], '\/', 6))}${element['file-name']}`
}
});
}))
);
I have so far been unable to get the second approach to work. Is it possible to do this? I think the problem lies in how to setup the map
operator with an array object. Is this right and can anyone point me in the right direction?
Edit:
Each object in the recordings array mentioned above has the following format:
{
"id": "477551",
"gen": "Troglodytes",
"sp": "troglodytes",
"ssp": "troglodytes",
"en": "Eurasian Wren",
"rec": "\u00c9tienne Leroy",
"cnt": "Poland",
"loc": "Hajn\u00f3wka, hajnowski, podlaskie",
"lat": "52.6907",
"lng": "23.6035",
"alt": "160",
"type": "song",
"url": "\/\/www.xeno-canto.org\/477551",
"file": "\/\/www.xeno-canto.org\/477551\/download",
"file-name": "XC477551-190503-Troglodyte [email protected]",
"sono": {
"small": "\/\/www.xeno-canto.org\/sounds\/uploaded\/ZWAQHOJFLZ\/ffts\/XC477551-small.png",
"med": "\/\/www.xeno-canto.org\/sounds\/uploaded\/ZWAQHOJFLZ\/ffts\/XC477551-med.png",
"large": "\/\/www.xeno-canto.org\/sounds\/uploaded\/ZWAQHOJFLZ\/ffts\/XC477551-large.png",
"full": "\/\/www.xeno-canto.org\/sounds\/uploaded\/ZWAQHOJFLZ\/ffts\/XC477551-full.png"
},
"lic": "\/\/creativecommons.org\/licenses\/by-nc-sa\/4.0\/",
"q": "A",
"length": "1:13",
"time": "08:00",
"date": "2019-05-03",
"uploaded": "2019-05-29",
"also": [
"Fringilla coelebs"
],
"rmk": "Singing seated or in flight",
"bird-seen": "yes",
"playback-used": "no"
}
Upvotes: 0
Views: 69
Reputation: 2598
I think you need to specify the type of created objects
return this.http.get<IXenoCantoResponse>(`${this.corsAnywhereUrl}${this.xenoCantoApiBaseUrl}${this.formatSearchTerm(searchTerm)}${this.recordingLength}`)
.pipe(
map(o => return new IXenoCantoResponse({
numRecordings: o.numRecordings,
numSpecies: o.numSpecies,
page: o.page,
numPages: o.numPages,
recordings: o.recordings.map((element: IVoice, index) => new IVoice({
id: index + 1,
url: `${element['sono']['full'].substr(0, this.getPosition(element['sono']['full'], '\/', 6))}${element['file-name']}`
})
});
}))
);
Upvotes: 1