Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to I load JSON data into Angular2 component

After running through many tutorials on tinterweb I have finally started to try and build something useful to me using Angular2 and I have come across my first issue. I cannot seem to load JSON data into my service component.

my people.json file is stored in a folder called data in the top folder.

people.json

"people":[
    { age: 40, name: "Jordan Houston" },
        { age: 38, name: "Robert Eastham" },
        { age: 23, name: "Josh Beh" },
        { age: 23, name: "Joseph Canina" },
        { age: 24, name: "Alexandra Wilkins" },
        { age: 22, name: "Kiersten Costanzo" },
        { age: 23, name: "Ku Sherwood" },
        { age: 25, name: "Arta Halili" },
        { age: 24, name: "Patrick Cooney" },
        { age: 23, name: "Z.A. Perr" },
        { age: 18, name: "Tyler Mulligan" },
        { age: 26, name: "Dennis Dempsey" },
        { age: 32, name: "Francis Yeager" },
        { age: 23, name: "Phil Belardi" }
]

I believe my issue lies in the friends.service.ts

friend.service.ts

import {Injectable} from 'angular2/core';
import {Http, HTTP_PROVIDERS} from 'angular2/http';

@Injectable()

export class FriendService { 

    friends:Array<any>;

    constructor(private http:Http) 
        {
            //console.log(">>friend.service.ts:constructor--")
            http.request('./data/people.json')
                    .subscribe(response => this.friends = response.json()));
    }

        getFriends()
        {
            //console.log(">>friend.service.ts:getFriends--")
            console.log(this.friends)
            return this.friends
        }   
}

friend.service.ts is used within the friend.component.ts

friend.component.ts

import { Component } from 'angular2/core'; 
import { FriendService } from 'app/friend.service';

@Component({
    selector: 'my-friends',
      providers: [FriendService],
        styles: [`
             div { 
                 background-color:#EFEFEF;
                 margin-bottom:15px;
                 padding:15px;
                 border:1px solid #DDD;
                 box-shadow:2px 2px 2px 0 rgba(0, 0, 0, 0.3);
                border-radius:3px;
            }
        h2 { 
            text-align: center;
        }
    `],
    template: `
        <h1>Hello from the {{ componentName }}!</h1>
        <div *ngFor="#f of friends">
            <h3>Name: {{ f.name }}</h3> 
            <h4>Age: {{ f.age }}</h4> 
        </div>
    `
})


export class FriendComponent {

    componentName: 'FriendComponent';

        constructor(private _friendService: FriendService) 
        {
        this.friends = _friendService.getFriends();
    }
} 

this lives within main.ts

main.ts

import { Component } from 'angular2/core';
import { bootstrap } from 'angular2/platform/browser';

import { FriendComponent } from 'app/friend.component';
import {HTTP_PROVIDERS} from 'angular2/http';


@Component({
  selector: 'my-app',
    directives: [FriendComponent],
  styles: [`
  h1 {
    color:#545454;
    background:#02A8F4;
    padding:15px;
    box-shadow:2px 2px 2px 0 rgba(0, 0, 0, 0.3);
  }
  `]
  template: `
  <div>
  <h1>Hello from the {{componentName}}.</h1>
  <my-friends></my-friends>
  </div>
  `
})
export class AppComponent {
  componentName: 'AppComponent'
}

bootstrap(AppComponent,[HTTP_PROVIDERS])

...and here is the index page...

<!DOCTYPE html>
<html>
<head>
  <script>document.write('<base href="' + document.location + '" />');</script>

  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <!--Add Bootstrap CSS Styles-->
  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css">

  <!-- IE required polyfills, in this exact order -->
  <script src="https://cdnjs.cloudflare.com/ajax/libs/es6-shim/0.34.1/es6-shim.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/systemjs/0.19.20/system-polyfills.js"></script>
  <script src="https://npmcdn.com/angular2/es6/dev/src/testing/shims_for_IE.js"></script>

  <!-- Angular polyfill required everywhere -->
  <script src="https://code.angularjs.org/2.0.0-beta.8/angular2-polyfills.js"></script>

  <script src="https://code.angularjs.org/tools/system.js"></script>
  <script src="https://code.angularjs.org/tools/typescript.js"></script>
  <script src="https://code.angularjs.org/2.0.0-beta.8/Rx.js"></script>
  <script src="https://code.angularjs.org/2.0.0-beta.8/angular2.dev.js"></script>
  <script src="https://code.angularjs.org/2.0.0-beta.8/router.dev.js"></script>
  <script src="https://code.angularjs.org/2.0.0-beta.8/http.dev.js"></script>

  <script>
      System.config({
        transpiler: 'typescript', 
        typescriptOptions: { emitDecoratorMetadata: true }, 
        packages: {
          'api': {defaultExtension: 'ts'}, 
          'app': {defaultExtension: 'ts'} 
        } 
      });
    System.import('app/main')
          .then(null, console.error.bind(console));
  </script>

</head>
<body class="container">

  <my-app>Loading...</my-app>

</body>
</html>

Any help would be greatly appreciated ;)

like image 340
Beaker Avatar asked Apr 20 '16 15:04

Beaker


1 Answers

In fact, it's because your data are loaded asynchronously. So within the constructor of your component, you initially get an undefined value.

constructor(private _friendService: FriendService) {
  this.friends = _friendService.getFriends();
}

To keep your constructor like that, you need to refactor your code to make the getFriends method of your service return an observable:

@Injectable()
export class FriendService { 
  constructor(private http:Http) {
  }

  getFriends() {
    return this.http.request('./data/people.json')
                 .map(res => res.json());
  }
}

Then you can use the async pipe into your component template:

template: `
    <h1>Hello from the {{ componentName }}!</h1>
    <div *ngFor="#f of friends | async">
        <h3>Name: {{ f.name }}</h3> 
        <h4>Age: {{ f.age }}</h4> 
    </div>
`
like image 142
Thierry Templier Avatar answered Nov 08 '22 13:11

Thierry Templier