Angular calling an Array from a service method() to my main component ; - javascript

In my api-service.ts
i have an array which contains some data in an Array.
public getData():Observable<any[]> {
return Observable.toString[ObsResult];
}
Then in my main component i am trying to call getData() method to display data in
main.componenet.html
service.getData().subscribe({result => console.log (result)});
I get the error TypeError: Cannot read property 'subscribe' of undefined
I am guessing this line is wrong but i am not sure what to put here
Observable.toString

There are multiple approaches you could use to solve the problem.
Method 1: More Native implementation
public getData(): Observable < any[] > {
return new Observable(observer => {
observer.next(ObsResult);
observer.complete();
});
}
Method 2: Angular (rxjs) Implementation
public getData(): Observable < any[] > {
return of(ObsResult);
}

If you have static data
example: const ObsResult = [1,2,3,4,5];
You can use
public getData():Observable<any[]> {
return Observable.of(ObsResult);
}
then you can subscribe to
service.getData().subscribe({result => console.log (result)});

Related

API call returns empty object when called from inside Angular service

I'm getting this only when I subscribe to the function that makes api call from inside the Angular service, so the object that subscribes to the function is empty. Here's my code snippet from my service:
getSchedules(): Observable<Schedule[]> {
this.http.get<TempSchedules[]>(this.apiUrl).subscribe(x => this.temp = x);
this.temp.forEach((e, i) => {
// Do something, this loop is never executed because this.temp is empty
});
// Some processing here
return something; }
Here is my http.get function somewhere inside the service:
getTempSchedules(): Observable<TempSchedules[]> {
return this.http.get<TempSchedules[]>(this.apiUrl);
}
From the above, this.temp is empty. Why is that?
I called the above function in the service constructor as
constructor(private http:HttpClient) {
this.getTempSchedules().subscribe(x => this.temp = x);
}
Here is a code snippet from a component that calls that function in the service:
ngOnInit(): void {
this.scheduleService.getTempSchedules().subscribe(x => this.tempSchedules = x);
}
The component works fine, so when I use the value this.tempSchedules in the html it is displayed correctly. What am I missing here?
It is not working because you are not getting the way observable works. It is async process and you need to be in subscribe block to get it. In case you want to do some funky stuff with the response before returning it to the component, then you should use map
getTempSchedules(): Observable<Schedule[]> {
return this.http.get<TempSchedules[]>(this.apiUrl)
.pipe(map(res => {
return res.forEach(() => {
// Do something, this loop will be executed
})
})) }
use it in component as :
ngOnInit(): void {
this.scheduleService.getTempSchedules().subscribe(x => this.tempSchedules = x);
}

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.

Angular2 observable with JSON root element

This is my first time ever working with angular observables and I'm a bit confused on how this works. I was given a mostly functioning angular CLI app that I just need to wire up to my already existing API.
I have a service with this function
public getApps(): Observable<ApplicationInterface[]> {
return this.http.get(url);
}
Then in my component, I have
public data: ApplicationInterface[];
ngOnInit() {
this.route.params
.subscribe(params => {
this.fetchData();
});
}
fetchData() {
this.service.getApps()
.subscribe(data => {
this.data = data;
});
}
My api endpoint returns a JSON structure of {"applications": []}
I can't seem to figure out how to access the array in that JSON hash.
If I console.log(data) in the subscribe block, it is the API response with the applications key that I expect, but if I change the data assignment to this.data = data.applications, ng build fails with Property 'applications' does not exist on type 'ApplicationInterface[]'
You should design the interface to be aligned with the response. If the response is object, than you need to have it like this also in the interface.
Try something like this (using the new HttpClient):
interface ApplicationInterfaceResponse {
applications: ApplicationInterface[];
}
public getApps(): Observable<ApplicationInterface[]> {
return this.httpClient
.get<ApplicationInterfaceResponse>(url)
.map(response => {
console.log(response.applications);
return data.applications;
});
}
If your return is of type ApplicationInterface[], then it's an array of ApplicationInterfaces, thus does not have a property called applications on it. This has nothing to do with your observable; it's fine. Rather, you've mistyped your variable.
If you don't need any other properties of data, you can map the value:
public getApps(): Observable<ApplicationInterface[]> {
return this.http.get(url).map(data => data.applications);
}
However, I recommend against this in most situations. If your object changes in the future, then you have to change this function and all attached subscriptions. Instead, you should create an interface for your response (your response right now does not match the type you're giving it), and use values of it as necessary.
The simplest fix is to indicate the correct form of the data that is returned by your service method since it doesn't actually return an array:
public getApps(): Observable<{applications:ApplicationInterface[]}> {
return this.http.get(url);
}
Now in your subscribe, you can get at the array as you would expect
.subscribe(e => this.data = e.applications)

Angular2 'this' is undefined

I have a code that looks like this:
export class CRListComponent extends ListComponent<CR> implements OnInit {
constructor(
private router: Router,
private crService: CRService) {
super();
}
ngOnInit():any {
this.getCount(new Object(), this.crService.getCount);
}
The ListComponent code is this
#Component({})
export abstract class ListComponent<T extends Listable> {
protected getCount(event: any, countFunction: Function){
let filters = this.parseFilters(event.filters);
countFunction(filters)
.subscribe(
count => {
this.totalItems = count;
},
error => console.log(error)
);
}
And the appropriate service code fragment from CRService is this:
getCount(filters) {
var queryParams = JSON.stringify(
{
c : 'true',
q : filters
}
);
return this.createQuery(queryParams)
.map(res => res.json())
.catch(this.handleError);
}
Now when my ngOnInit() runs, I get an error:
angular2.dev.js:23925 EXCEPTION: TypeError: Cannot read property
'createQuery' of undefined in [null]
ORIGINAL EXCEPTION:
TypeError: Cannot read property 'createQuery' of undefined
So basically, the this in the return this.createQuery(queryParams) statement will be null. Does anybody have an idea how is this possible?
The problem is located here:
gOnInit():any {
this.getCount(new Object(), this.crService.getCount); // <----
}
Since you reference a function outside an object. You could use the bind method on it:
this.getCount(new Object(), this.crService.getCount.bind(this.crService));
or wrap it into an arrow function:
this.getCount(new Object(), (filters) => {
return this.crService.getCount(filters));
});
The second approach would be the preferred one since it allows to keep types. See this page for more details:
https://basarat.gitbooks.io/typescript/content/docs/tips/bind.html
To fix this error I yanked all the innards out of my function causing the error and threw it in another function then the error went away.
example:
I had this function with some code in it
this.globalListenFunc = renderer.listenGlobal('document', 'click', (event) => {
// bunch of code to evaluate click event
// this is the code that had the "this" undefined error
});
I pulled the code out and put it in an external public function, here's the finished code:
this.globalListenFunc = renderer.listenGlobal('document', 'click', (event) => {
this.evaluateClick(event);
});
evaluateClick(evt: MouseEvent){
// all the code I yanked out from above
}

AngularJs 2: How to debug a service call? (es6 syntax)

THE SITUATION:
I am just learning Angular2. I wanted to debug the call to a service.
The service has been properly called, as I can see in the view.
I also want to log to content of variable that hold the result, but it is not working as i would except.
THE SERVICE:
export class ListService
{
getList()
{
return Promise.resolve(LIST);
}
}
THE CALL (from the list component):
export class ListComponent implements OnInit
{
list: Item[];
constructor(
private _router: Router,
private _listService: ListService
) { }
getList()
{
this._listService.getList().then(list => this.list = list);
}
ngOnInit()
{
this.getList();
}
}
LOG ATTEMPT 1:
list is the variable containing the list of items. In the view it properly show the content. So i would expect to log it and see its content.
getList()
{
this._listService.getList().then(list => this.list = list);
console.log(list)
}
But when i get this error instead:
EXCEPTION: ReferenceError: list is not defined in [null]
LOG ATTEMPT 2:
Trying to get the correct syntax:
getList()
{
this._listService.getList().then(list => this.list = list);
console.log(this.list)
}
There are no errors now. But in the console it shows undefined.
But the service has already been called. So it should contain the content
THE QUESTION:
Considering that i am using Angular2 - Ecmascript 2016
What is the proper syntax to log the call of a service?
Thank you!
In fact this.list is set within the callback registered in the then method. So you should use something like that:
getList()
{
this._listService.getList().then(list => {
this.list = list;
console.log(list);
console.log(this.list);
});
}
If you put the console.log(this.list); right the promise, the result won't be probably there so this.list probably doesn't set...

Categories

Resources