Reading an specific key from JSON using Service - javascript

I am new to all JavaScript and angular. so I am struggling to do the following:
I have the following service, to read X from a local JSON file. The X is what user select from a dropdownbox:
getBySector(sector){
this.http.get('../../assets/Sectors.json').map(res => res).subscribe
(res => {
this.SectorsArray = res as ISectors[];
this.SectorsArray= res.find(item=>item.Sector===sector);
console.log(this.industrySectorsArray);
return this.industrySectorsArray;
},
(err: HttpErrorResponse) => {
console.log (err.message);
}
)
}
as an additional note, I have an interface which is ISector and matches the JSOn file.
The above code give me in Console the exact thing I expect. which is the following:
{IndustrySector: "Households", isSelected: "false", dataSubjectCategories: Array(2), dataTypeCategories: "Data", SubIndustries: Array(2)}
HOW can I return the above object/json output to ms TS file where I have called the service?
I have done the followings which are failed:
//even this failed:
console.log(this.readjsonService.getBySector(mission));
//
var output:Isector;
output=this.readjsonService.getBySector(mission)
// cannot subscribe to it as well
BTW, the find gives me the following error:
error TS2339: Property 'find' does not exist on type 'Object'.
UPDATE:
I solved the issue the code had with the help of people who replied. But the code got another error, although it works fine. t says:
"Cannot read property 'dataSubjectCategories' of undefined"
dataSubjectCategories is one of the key in the ISector: here is the ISector:
export interface ISectors {
IndustrySector: string;
isSelected: string;
dataSubjectCategories:string[];
dataTypeCategories:string[];
SubIndustries:[{
IndustrySector: string;
isSelected: string;
dataSubjectCategories:string[];
dataTypeCategories:string[];
SubIndustries:[{}]
}]
}
Please help to resolve this. Thanks a lot.

Normally, your service should just be returning the Observable and should not include the subscribe. Best practice suggests that you subscribe as close to the UI as possible.
My service methods look like this:
getProducts(): Observable<IProduct[]> {
return this.http.get<IProduct[]>(this.productUrl).pipe(
tap(data => console.log('All: ' + JSON.stringify(data))),
catchError(this.handleError)
);
}
getProduct(id: number): Observable<IProduct | undefined> {
return this.getProducts().pipe(
map((products: IProduct[]) => products.find(p => p.productId === id))
);
}
Using the generic parameter on the get: get<IProduct[]> helps Angular automatically map the returned response to an array of data, ISectors in your example.
The calling code in the component then looks like this:
getProduct(id: number) {
this.productService.getProduct(id).subscribe(
product => this.product = product,
error => this.errorMessage = <any>error);
}
Notice that here is where we subscribe. It then gets the product in the first function passed to the subscribe method.
You can find the complete example here: https://github.com/DeborahK/Angular-GettingStarted/tree/master/APM-Final

Related

How to handle different kind of data getting fron an observable?

I am trying to use switchMap operator. But it should call different http requests based upon the params. So for different http requests the data from subscribe will also be deifferent. How to properly handle that data. Right now i am getting typescript error..My code..
ngOnInit(){
this.route.params.pipe(switchMap(params => {
if (params === 'friends') {
return this.http.get('some url to get friendList')
} else if (params === 'chats') {
return this.http.get('some url to get chats')
}
})).subscribe((result: {message: string, friendList: []} | {message: string, chats: []}) => {
console.log(result)
})
}
Here basically i am getting different structured data for calling two different api based upon condition. So i am trying to work with the result which i am getting from subscribe like..
.subscribe((result: {message: string, friendList: []} | {message: string, chats: []}) => {
if(result.friendList) {
// do something
} else if (result.chats) {
//do something
}
})
Here i am getting typescript errors on using like result.friendList or result.chats . So how should i work with the result?
You can change the type of the result to any and then the conditions will work properly and the typescript will pass without errors.
.subscribe((result: any) => {
if(result.friendList) {
// do something
} else if (result.chats) {
//do something
}
})
if you want to specify the type you can make it with that:
{message: string, friendList: [] , chats: []}
and when one of the arrays is empty you can check the lengths and reach the condition

Angular 9 typecast issue after http response

I have a component which retrieves a student info from an api upon its initialization.
This is the onIniti code on my cmponent-version1
ngOnInit(): void {
if(!this.student) {
this.studentsService.getStudentDetail(this.id).subscribe(
(response: Student) => {
this.student = response;
},
error => console.log(error)
)
}
}
and here is the function inside my student-service-version1
getStudentDetail(id: number): Observable<Student> {
return this.httpClient.get<Student>(`${this.studentsUrl}${id}/`, this.baseService.httpOptions);
}
Everything works fine. Now, just for didactic purpose (I'm new to javascript/typescript), I'd like to refactor my service in order to use a single get function which returns the list of students when called without parameter, and instead return a student detail info when called with a specific id.
This is the students-service-version2
getStudents(id?: number): Observable<Student[]> {
if(id)
return this.httpClient.get<Student[]>(`${this.studentsUrl}${id}/`, this.baseService.httpOptions);
else
return this.httpClient.get<Student[]>(this.studentsUrl, this.baseService.httpOptions);
}
Given that the signature of my function states it returns a students array observable, in my component I need a sort of typecasting from Student[] to Student. This is how I do it:
component-version2
ngOnInit(): void {
if(!this.student) {
this.studentsService.getStudents(this.id).subscribe(
(response: Student[]) => {
this.student = response[0] as Student;
},
error => console.log(error)
)
}
}
This doesn't work so after the init, student var remains undefined. I do not understand why, everything seems correct to me (although this refactoring it's not a good idea. Again, I just want to understand the error behind)
I'vs also try
this.student = response.pop() as Student; Same result, not working.
ngOnInit(): void {
if(!this.student) {
this.studentsService.getStudents(this.id).subscribe(
(response: Student[]) => {
// Hope, this.student will have type as any, public student: any
this.student = !this.id ? response[0] as Student : response as Student[];
},
error => console.log(error)
)
}
}
Always, try to return an array to avoid conflicts. In the above code,
the ternary operator will do your work. As, if you have an id that
means you are asking for particular student information otherwise you
are asking for all student records.
your service should be yelling at you right now because you're lying to the compiler... your return type isn't Observable<Student[]> its Observable<Student[] | Student>... i don't agree with the principal of one function for both single and list gets at all, but you could force it to be a list in the single case...
return this.httpClient.get<Student>(`${this.studentsUrl}${id}/`, this.baseService.httpOptions).pipe(
map(student => [student])
);
no typecasting will convert something to an array if its not an array. you need to explicitly make it an array if that's waht you want.
Overload the signature of your method as follows:
class StudentService {
get(id: number) | Observable<Student>;
get(): Observable<Student[]>;
get(id: number | undefined): Observable<Student[]> | Observable<Student> {
if(id !== undefined)
return this.httpClient.get<Student[]>(`${this.studentsUrl}${id}/`, this.baseService.httpOptions);
else
return this.httpClient.get<Student>(this.studentsUrl, this.baseService.httpOptions);
}
}
Notice how the method has been renamed to make sense in either case, how the return type is correlated with the presence of the id parameter, and how the check has been modified to accommodate the possibility of 0 as a valid id.

Using Types in Angular 2 with TypeScript

I have the following method in my AppComponent:
connectToTweetStream() {
this._tweetService.connectToStream()
.subscribe(
tweet => {
this.tweets.push(tweet);
},
error => this.errorMessage = <any>error
);
}
When I declare tweets as an array of any: tweets: any[] = []; at the top of my AppComponent Class everything works great. However, I want tweets to be of type Tweet, so tweets: Tweet[] = [];.
When I make this change I get the error Argument of type '{}' is not assignable to parameter of type 'Tweet'. And indeed when I hover over tweet on line 4 of the code above it is of type {}. How can I fix this so that tweets can be an array of Tweet objects?
In your subscription cast the type of each item
subscribe(
(tweet as Tweet) => {
this.tweets.push(tweet);
},
error => this.errorMessage = <any>error
);

Fail to return a string from in a function from another function

I have this 3 functions that triggers POST api calls, and I want to return a succsess/failure message to whoever calls it (Observable<string>).
So the messages are similar and I didnt wan to repeat myself then I added a new function to get success message. But from some reason it dosent work, I see a blank page when I run the app, but if instead of calling getSuccessMessage I just pass a regular string ("Something") it works...
weird, those are my funcs:
export enum ListType {Cars, Animals, Books}
public updateOne(carList: Car[]): Observable<string> {
return this._myApiSevice.postCarsNewOrder(carList)
.map(response => this.getSuccessMessage(ListType.Cars)) //update succeeded
.catch(error => Observable.of("FAILURE: post to Cars did not succeed!"));
}
public updateTwo(animalList: Animal[]): Observable<string> {
return this._myApiSevice.postAnimalsNewOrder(animalList)
.map(response => this.getSuccessMessage(ListType.Animals))
.catch(error => Observable.of("FAILURE: post to Animals did not succeed!"));
}
public updateThree(bookList: Book[]): Observable<string> {
return this._myApiSevice.postBooksNewOrder(bookList)
.map(response => this.getSuccessMessage(ListType.Books)) //update succeeded
.catch(error => Observable.of("FAILURE: post to Books did not succeed!"));
}
public getSuccessMessage(listType: ListType): string {
return "SUCCESS: post to " + ListType[listType] + "succeed!";
}
do you see something wrong?
this is the error in the console:
EXCEPTION: Error: Uncaught (in promise): Cannot resolve all parameters
for 'MyCmp'(undefined, ElementRef, MdDialog). Make sure that
all the parameters are decorated with Inject or have valid type
annotations and that 'MyCmp' is decorated with Injectable.
the enum is declerated in another class, this importing the class the the enums are coming from.
and also if you have a suggestion for me how to gather also the failure message into a one function with the success message it will be lovely, thanks#!
To get the value of a string from an enum type in typescript you need to do the following
enum ListType {
Cars,
Animals,
Books
}
var booksStr = ListType[ListType.Books];
Here's a good explanation for why this is the case https://basarat.gitbooks.io/typescript/content/docs/enums.html
So your function would be something like
public getSuccessMessage(listType: ListType): string {
return "SUCCESS: post to " + ListType[ListType.listType] + "succeed!";
}

Angular 2 run interface during http get

I've worked out how to import a json object from http get and list the results out via *ngFor.
What I can't work out is how to run an interface against it. My interface file is here:
import {Offer} from './offer';
and I have my http get request here:
constructor(private _httpService: HTTPTestService) { }
offers: "";
onTestGet() {
this._httpService.getOffers()
.subscribe(
data => { this.offers = data.offers; },
error => alert(error),
() => console.log("Finished")
);
}
But how do I run the "Offer" interface past the object I get back?
You need to be careful with interfaces in TypeScript. Interfaces are only for design and type checking but don't exist at runtime.
You can define an array of Offer for offers and cast the data you receive to Offer[]. But each element isn't of type Offer. This allows to check the structure of objects during compilation...
Here is a sample:
constructor(private _httpService: HTTPTestService) { }
offers: Offer[]; // <----
onTestGet() {
this._httpService.getOffers()
.subscribe(
data => { this.offers = <Offer[]>data.offers; }, // <----
error => alert(error),
() => console.log("Finished")
);
}

Categories

Resources