Getting an object array from an Angular service

153,772

Take a look at your code :

 getUsers(): Observable<User[]> {
        return Observable.create(observer => {
            this.http.get('http://users.org').map(response => response.json();
        })
    }

and code from https://angular.io/docs/ts/latest/tutorial/toh-pt6.html (BTW. really good tutorial, you should check it out)

 getHeroes(): Promise<Hero[]> {
    return this.http.get(this.heroesUrl)
               .toPromise()
               .then(response => response.json().data as Hero[])
               .catch(this.handleError);
  }

The HttpService inside Angular2 already returns an observable, sou don't need to wrap another Observable around like you did here:

   return Observable.create(observer => {
        this.http.get('http://users.org').map(response => response.json()

Try to follow the guide in link that I provided. You should be just fine when you study it carefully.

---EDIT----

First of all WHERE you log the this.users variable? JavaScript isn't working that way. Your variable is undefined and it's fine, becuase of the code execution order!

Try to do it like this:

  getUsers(): void {
        this.userService.getUsers()
            .then(users => {
               this.users = users
               console.log('this.users=' + this.users);
            });


    }

See where the console.log(...) is!

Try to resign from toPromise() it's seems to be just for ppl with no RxJs background.

Catch another link: https://scotch.io/tutorials/angular-2-http-requests-with-observables Build your service once again with RxJs observables.

Share:
153,772

Related videos on Youtube

Nho Jotom
Author by

Nho Jotom

Updated on July 09, 2022

Comments

  • Nho Jotom
    Nho Jotom almost 2 years

    I am new to Angular (and Javascript for that matter). I've written an Angular service which returns an array of users. The data is retrieved from an HTTP call which returns the data in JSON format. When logging the JSON data returned from the HTTP call, I can see that this call is successful and the correct data is returned. I have a component which calls the service to get the users and an HTML page which displays the users. I cannot get the data from the service to the component. I suspect I am using the Observable incorrectly. Maybe I'm using subscribe incorrectly as well. If I comment out the getUsers call in the ngInit function and uncomment the getUsersMock call, everything works fine and I see the data displayed in the listbox in the HTML page. I'd like to convert the JSON data to an array or list of Users in the service, rather then returning JSON from the service and having the component convert it.

    Data returned from HTTP call to get users:

    [
        {
            "firstName": "Jane",
            "lastName": "Doe"
        },
        {
            "firstName": "John",
            "lastName": "Doe"
        }
    ]
    

    user.ts

    export class User {
        firstName: string;
        lastName: string;
    }
    

    user-service.ts

    ...
    @Injectable
    export class UserService {
        private USERS: User[] = [
            {
                firstName: 'Jane',
                lastName: 'Doe'
            },
            {
                firstName: 'John',
                lastName: 'Doe'
            }
        ];
    
        constructor (private http: Http) {}
    
        getUsersMock(): User[] {
            return this.USERS;
        }
    
        getUsers(): Observable<User[]> {
            return Observable.create(observer => {
                this.http.get('http://users.org').map(response => response.json();
            })
        }
    ...
    

    user.component.ts

    ...
    export class UserComponent implements OnInit {
        users: User[] = {};
    
        constructor(private userService: UserService) {}
    
        ngOnInit(): void {
            this.getUsers();
            //this.getUsersMock();
        }
    
        getUsers(): void {
            var userObservable = this.userService.getUsers();
            this.userObservable.subscribe(users => { this.users = users });
        }
    
        getUsersMock(): void {
            this.users = this.userService.getUsersMock();
        }
    }
    ...
    

    user.component.html

    ...
    <select disabled="disabled" name="Users" size="20">
        <option *ngFor="let user of users">
            {{user.firstName}}, {{user.lastName}}
        </option>
    </select>
    ...
    

    !!! UPDATE !!!

    I had been reading the "heroes" tutorial, but wasn't working for me so I went off and tried other things. I've re-implemented my code the way the heroes tutorial describes. However, when I log the value of this.users, it reports undefined.

    Here is my revised user-service.ts

    ...
    @Injectable
    export class UserService {
        private USERS: User[] = [
            {
                firstName: 'Jane',
                lastName: 'Doe'
            },
            {
                firstName: 'John',
                lastName: 'Doe'
            }
        ];
    
        constructor (private http: Http) {}
    
        getUsersMock(): User[] {
            return this.USERS;
        }
    
        getUsers(): Promise<User[]> {
            return this.http.get('http://users.org')
                .toPromise()
                .then(response => response.json().data as User[])
                .catch(this.handleError);
        }
    ...
    

    Here is my revised user.component.ts

    ...
    export class UserComponent implements OnInit {
        users: User[] = {};
    
        constructor(private userService: UserService) {}
    
        ngOnInit(): void {
            this.getUsers();
            //this.getUsersMock();
        }
    
        getUsers(): void {
            this.userService.getUsers()
                .then(users => this.users = users);
    
            console.log('this.users=' + this.users); // logs undefined
        }
    
        getUsersMock(): void {
            this.users = this.userService.getUsersMock();
        }
    }
    ...
    

    !!!!!!!!!! FINAL WORKING SOLUTION !!!!!!!!!! This is all the files for the final working solution:

    user.ts

    export class User {
        public firstName: string;
    }
    

    user.service.ts

    import { Injectable }     from '@angular/core';
    import { Http, Response } from '@angular/http';
    import { Observable }     from 'rxjs/Observable';
    
    import 'rxjs/add/operator/catch';
    import 'rxjs/add/operator/map';
    
    import { User } from './user';
    
    @Injectable()
    export class UserService {
        // Returns this JSON data:
        // [{"firstName":"Jane"},{"firstName":"John"}]
        private URL = 'http://users.org';
    
        constructor (private http: Http) {}
    
        getUsers(): Observable<User[]> {
            return this.http.get(this.URL)
                .map((response:Response) => response.json())
                    .catch((error:any) => Observable.throw(error.json().error || 'Server error'));
        }
    }
    

    user.component.ts

    import { Component, OnInit }   from '@angular/core';
    import { Router }              from '@angular/router';
    
    import { User }        from './user';
    import { UserService } from './user.service';
    
    
    @Component({
        moduleId: module.id,
        selector: 'users-list',
        template:  `
            <select size="5">
                <option *ngFor="let user of users">{{user.firstName}}</option>
            </select>
        `
    })
    
    export class UserComponent implements OnInit{
        users: User[];
        title = 'List Users';
    
        constructor(private userService: UserService) {}
    
        getUsers(): void {
            this.userService.getUsers()
                .subscribe(
                    users => {
                        this.users = users;
                        console.log('this.users=' + this.users);
                        console.log('this.users.length=' + this.users.length);
                        console.log('this.users[0].firstName=' + this.users[0].firstName);
                    }, //Bind to view
                                err => {
                            // Log errors if any
                            console.log(err);
                        })
        }
    
        ngOnInit(): void {
            this.getUsers();
        }
    }
    
  • Sefa
    Sefa over 7 years
    You are right about your point. Consider adding working example too.
  • jmachnik
    jmachnik over 7 years
    You can use the working example in Hero Tutorial. It works just fine. angular.io/resources/live-examples/toh-6/ts/plnkr.html
  • Nho Jotom
    Nho Jotom over 7 years
    Thanks jmachnik. I updated my question with additional information. The reason my code looked the way it did is I originally implemented it just as described in the heroes tutorial, but was getting 'undefined' for my User[] in the component, so I went off and tried other things. The code now looks like the heroes tutorial, but I'm still getting undefined. Any clues?
  • Nho Jotom
    Nho Jotom over 7 years
    jmachnik, it is working now. I'm glad you referenced an "Observable" tutorial rather then a "Promise" tutorial as I know the former is what I shoud be using (pretty much replaces Promise).
  • Nho Jotom
    Nho Jotom over 7 years
    jmachnik, it is working now. I'm glad you referenced an "Observable" tutorial rather then a "Promise" tutorial as I know the former is what I should be using (pretty much replaces Promise). At first, this still didn't work for me. I believe I had two problems: 1) My template had an error. I only found this out by deleting the HTML file and putting the HTML directly in the templateUrl field in the component and apparently fixing an unknown problem. 2) Logging the returned value.
  • Nho Jotom
    Nho Jotom over 7 years
    ...I still have much to learn about Java/TypeScript, but solved this problem as well. These two problems prevented me from seeing the returned data anywhere. Who knows, it may have been working all along (thought I doubt it). I will update my question with the final working solution soon.
  • Nho Jotom
    Nho Jotom over 7 years
    One additional comment...originally I had this as the declaration of the Users array in the component: groupsKeywords: GroupKeyword[] = {}; Which I saw in an example. This didn't work, but this declaration did: groupsKeywords: GroupKeyword[];
  • Mohammad Norhamizan
    Mohammad Norhamizan over 7 years
    @NhoJotom the reason why your console.log(...) is showing undefined is because there exists asynchronous code in your code. Hence, console.log(...) would show as undefined as it may have been executed at the time where your data is not received yet. link