I'm fairly new to Angular and I'm trying to get only certain values from the Http response object.
In my service, I'm doing a get request to fetch weather data for a given city like so:
export class CityService {
private baseUrl = 'https://api.openweathermap.org';
constructor(private http: HttpClient) { }
getCity(name: string){
return this.http.get(`${this.baseUrl}/data/2.5/weather?q=${name}&appid=${environment.weatherApiKey}`);
}
}
Now, in the component, I'm logging out the response like so:
ngOnInit(): void {
this.cityService.getCity('lucija').subscribe(data => {
console.log(data)
});
}
The response itself it's just one object with many fields (also nested ones), which most of them I do not need.
I've also set up an interface where I would like to "save" in those certain response fields:
export interface City {
name: string;
description: string;
icon: string;
main: object;
search: string;
}
How can I do that? Cheers!
EDIT:
Based on the answer below I got 2 errors, which I resolved like so:
getCity(name: string): Observable<City>{
return this.http.get(`${this.baseUrl}/data/2.5/weather?q=${name}&appid=${environment.weatherApiKey}`)
.pipe(map((res: any) => <City>{
name: res.name,
description: res.weather[0].description,
icon: `http://openweathermap.org/img/w/${res.weather[0].icon}.png`,
main: res.main,
search: name
}));
One solution could be to map the object in your service. Then your service will return the City Object.
export class CityService {
private baseUrl = 'https://api.openweathermap.org';
constructor(private http: HttpClient) { }
getCity(name: string): Observable<City>{
return this.http.get(`${this.baseUrl}/data/2.5/weather?q=${name}&appid=${environment.weatherApiKey}`)
.pipe(map((res) => { return { name: res.cityName }; }); // only added name as example. In the final code map all the values to the correct City field.
}
}
If you do not want your service to always return the City object you can do this mapping in your component.
Related
I want to return this object on every response:
class Response<T> {
success: boolean
message: string
data: T
}
but built in serializer can't process it because it waits for object which is under serialization. This is my solution. I created a custom response serializer and inherit built in one and map response. It works excellent for now! Offered me better way please.
export interface PlainLiteralObject {
[key: string]: any;
}
#Injectable()
export class ResponseSerializerInterceptor extends ClassSerializerInterceptor {
public intercept(context: ExecutionContext, next: CallHandler<any>): Observable<any> {
const contextOptions = super.getContextOptions(context);
const options = {
...super.defaultOptions,
...contextOptions,
};
return next.handle().pipe(map((res: Response<PlainLiteralObject> | Response<Array<PlainLiteralObject>>) => {// data property holds object which is under serialization
const data = super.serialize(res.data, options);
res.data = data;
return res;
}));
}
}
I'm new in angular and working on spring+angular project, I have 2 classes called questions and answers.
questions.ts
export class Questions {
private questionDescription: string;
private id: string;
private answers: Answers[] = [];
// getter setters
answers.ts
export class Answers {
private answerDescription: string;
private isVisible: boolean;
private id: string;
private voteCounter: number;
// getter setters
In my component.ts,i fetch the data from webservice. Here's my service;
base_url: string = "http://localhost:8080";
constructor(private http: HttpClient) { }
getQuestion(id: string): Observable<HttpResponse<Questions>> {
return this.http.get<Questions>(this.base_url + "/question" + "/" + id, { observe: 'response' });
}
This is my component ;
constructor(private activatedRoute: ActivatedRoute, private restService: RestcallService) { }
public id: string;
public question: Questions ;
public answers: Answers[] = [];
ngOnInit() {
this.id = this.activatedRoute.snapshot.paramMap.get('id');
this.restService.getQuestion(this.id).subscribe(response => {
if (response.status == 200) {
this.question = new Questions("");
Object.assign(this.question, response.body);
this.answers = this.question._answers;
}
})
}
After the line "this.answers=this.question._answers" , i use "answers" array in my component.html with [ngModel)] and it works, but i can't read property values of answer array outside of subscribe method,i have a button and this button calls "results()" function on click. I need to perform some calculations after reading object properties but i can't read. Below code prints "undefined" in console.
results() {
console.log(this.answers[0]._answerDescription); // prints undefined
}
When i change the method like this;
results() {
console.log(this.answers); // prints the array in console
}
How can i achieve this?
I have my service as PortAllocationService below
#Injectable({
providedIn: 'root'
})
export class PortAllocationService {
businessSwitchName: any;businessSwitchIp: any;businessSwitchportName: any;
businessSwitchNodeId: any;routerName: any;routerIp: any;routerDetailsportName: any;
routernodeID: any;aggSwitchName: any;aggSwitchPort: any;aggNodeIP: any;
aggNodeId: any;serviceName: any;convertorDetails: any;handoffPort: any;qosLoopingPort: any;
constructor(private http:HttpClient) { }
portService(da){
return this.http.post(url.portAllocationUrl , da).
subscribe ((response:any) => {
//Port Allocation response is mapped here
console.log(response);
// businessSwitchDetails
this.businessSwitchName = response.businessSwitchDetails.nodeName;
this.businessSwitchIp = response.businessSwitchDetails.nodeIP;
});
}
and my component as below
export class WimaxFormComponent {
data : any = {};
btsIp :any; vCategory:any;nVlan:any;
businessSwitchName:any;businessSwitchIp:any;businessSwitchportName:any;
routerName:any;routerIp:any;aggSwitchName:any;aggSwitchPort:any;
routerDetailsportName:any;routernodeID:any;aggNodeIP: any;aggNodeId: any;
businessSwitchNodeId: any;serviceName: any;convertorDetails: any;
handoffPort: any;qosLoopingPort: any;
serviceId: any;serviceType: any;customerName: any;
vReservedValue:boolean;cVlan: string;sVlan: any;
path: string;
constructor(
private service: PortAllocationService){
}
onChange(){
let portAllocationData = {
"serviceAttribute": {
"serviceType": this.serviceType,
"category": "category",
"name": this.serviceId
},
"btsIp": this.btsIp
}
console.log(portAllocationData);
this.service.portService(portAllocationData);
}
When i call the onChange function the call is made to service and we get the response from server . But i want to access all variable values from my service to Component like for example i have tried in constructor and onChange both as
this.businessSwitchName = service.businessSwitchName // this is coming as undefined
Could you please let me know how to access the variable values into component.
Rather than subscribing to the API call in the service itself, I would simply return the observable made by http.post(). And then move the subscribe to the component itself:
Service:
portService(da){ return this.http.post(url.portAllocationUrl , da) });
Component:
this.service.portService(portAllocationData).subscribe(response => {
// Do stuff with the response here
});
However, if you really want to keep the variables in the service, I would put the API call in the constructor of the service, change the fields in the service to start with an underscore (or some other local/private identifier) and then have get methods for each variable you want to be able to access.
Service:
get businessSwitchName() {
return this._businessSwitchName;
}
Component:
this.service.businessSwitchName
So basically what I want to achieve is watching/listening objects changing inside of array within an injectable service using setters and getters to manipulate it's data
eg
#Injectable()
export class StorageService {
protected items: Array<any> = [];
constructor(private storage: Storage) {
this.storage.ready().then(() => {
StorageService.getGetters().forEach((get) => {
this.storage.get(get).then(res => this.items[get] = res);
});
});
}
public static getGetters(): string[] {
return Object.keys(this.prototype).filter(name => {
return typeof Object.getOwnPropertyDescriptor(this.prototype, name)["get"] === "function"
});
}
get Storage() {
return this.storage;
};
ClearStorage() {
this.storage.clear();
}
protected Setter(key: string, value: any): void {
this.items[key] = value;
this.storage.set(key, value);
}
protected Getter(key: string): any {
return this.items[key];
}
set User(value: User) {
this.Setter('User', value);
}
get User(): User {
return this.Getter('User');
}
}
where User interface is :
export interface User {
id: number;
role_id: number;
name: string;
email?: string;
}
now in any component or service/provider I can DI my StorageService so I can access the User getter.
so:
storage.User.name = 'testing';
now the name is changed , but I have no way to track that , so I can update my storage!
to update my storage I would do:
storage.User.name = 'testing';
storage.User = storage.User;
which is working , but I need a way to listen to any changes happens to the object properties, so I can update my storage...
I searched alot , and all I can find is watching components #Input() , which is not working in my case.
Hopefully I made my point clear.
I have the following method in a service I've created:
getPost(nid: string): Observable<Post[]>{
let url = "http://test.co.uk/api/v1/basic/" + nid;
return this.http.get(url, {headers: this.headers}).map(res => res.json() as Post).catch(err => {
return Observable.throw(err);
});
}
And this is the class of my component:
export class PostDetailComponent implements OnInit {
posts: Post[] = [];
post: Post = new Post();
constructor(
private route: ActivatedRoute,
private postService: PostService
) { }
ngOnInit() {
this.route.params.switchMap((params: Params) => {
let nid = params ['nid'];
return this.postService.getPost(nid); }).subscribe(res => {
console.log(res)
this.post = res as Post;
}, err =>{
console.log(err);
});
}
}
The JSON feed looks like this(yes one object in the array):
[
{
"nid":"3",
"title":"When Unity meets Vuforia",
"body":"<p>Unless you have been living under a rock in the past 7 - ...",
"uid":"admin",
"path":"\/node\/3",
"field_article_image":"http:\/\/test.co.uk\/sites\/default\/files\/when-unity-meets-vuforia_0.jpg?itok=BGYaotay"
}
]
So in my template, if I print {{post}} I get [object Object] on the screen.
If I print {{post | json}} I get the row JSON feed.
And finally, if I print {{post.title}} or {{post?.title}} I don't get anything.
I also have a class Post that is looking like this:
export class Post{
constructor(
public nid?: string,
public title?: string,
public body?: string
public image?: string
){
}
}
Any hints?
You are assigning an array into what should be a single object. Copy the first element of the array into the post variable
this.post = res[0] as Post
Side note: It's incorrect to assign a raw object to a class instance. In this case, your this.post.constructor won't exist and this.post instanceof Post == false.
You could do Object.assign(this.post, res[0]) but you may need to clear existing properties if not all properties are always present.
I prefer to define object shapes as interfaces instead, then you would not have that problem because all the interface information is removed at runtime, whereas a class does emit some code instead of just doing static type checks at compilation time