webta.st.ic
webta.st.ic

Reputation: 5169

Load JSON content from a local file with http.get() in Angular 2

I'm trying to load a local JSON file with http.get() in Angular 2. I tried something that I found here on Stack Overflow. It looks like this:

This is my app.module.ts where I import the HttpModule and the JsonModule from @angular/http:

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { HttpModule, JsonpModule } from '@angular/http';
import { RouterModule, Routes } from '@angular/router';

import { AppComponent } from './app.component';
import { NavCompComponent } from './nav-comp/nav-comp.component';
import { NavItemCompComponent } from './nav-comp/nav-item-comp/nav-item-comp.component';


@NgModule({
    declarations: [
        AppComponent,
        NavCompComponent,
        NavItemCompComponent
    ],
    imports: [
        BrowserModule,
        FormsModule,
        HttpModule,
        JsonpModule,
        RouterModule.forRoot(appRoutes)
    ],
    providers: [],
    bootstrap: [AppComponent]
})

export class AppModule { }

In my component, I import Http and Response from @angular/http. Then I have a function called loadNavItems(), where I try to load my JSON content with a relative path using http.get() and print the result with console.log(). The function is called in ngOnInit():

import { Component, OnInit } from '@angular/core';
import { Http, Response } from '@angular/http';

@Component({
    selector: 'app-nav-comp',
    templateUrl: './nav-comp.component.html',
    styleUrls: ['./nav-comp.component.scss']
})
export class NavCompComponent implements OnInit {

    navItems: any;

    constructor(private http: Http) { }

    ngOnInit() {
        this.loadNavItems();
    }

    loadNavItems() {
        this.navItems = this.http.get("../data/navItems.json");
        console.log(this.navItems);
    }
}

My local JSON file looks like this:

[{
        "id": 1,
        "name": "Home",
        "routerLink": "/home-comp"
    },
    {
        "id": 2,
        "name": "Über uns",
        "routerLink": "/about-us-comp"
    },
    {
        "id": 3,
        "name": "Events",
        "routerLink": "/events-comp"
    },
    {
        "id": 4,
        "name": "Galerie",
        "routerLink": "/galery-comp"
    },
    {
        "id": 5,
        "name": "Sponsoren",
        "routerLink": "/sponsoring-comp"
    },
    {
        "id": 6,
        "name": "Kontakt",
        "routerLink": "/contact-comp"
    }
]

There aren't any errors in the console, and I just get this output:

Enter image description here

In my HTML template I would like to loop the items like this:

<app-nav-item-comp *ngFor="let item of navItems" [item]="item"></app-nav-item-comp>

I made this with a solution I found here on Stack Overflow, but why doesn't it work?

Edit relative path:

I also get a problem with my relative path, but I'm sure it's the right one when I use ../data/navItems.json. In the screenshot, you can see the nav-comp.component.ts file, where I load the JSON content using a relative path from the JSON file which is in the folder called data? What's wrong? Does the console print an 404 error, because it can't find my JSON file from the relative path?

Enter image description here

Upvotes: 62

Views: 197937

Answers (8)

Philip Owino
Philip Owino

Reputation: 51

Put your navItems.json file in the "assets" folder. Angular knows how to look inside the assets folder. So instead of:

loadNavItems() {
    this.navItems = this.http.get("../data/navItems.json");
    console.log(this.navItems);
}

Change the path to simply:

loadNavItems() {
    this.navItems = this.http.get("assets/navItems.json");
    console.log(this.navItems);
}

Upvotes: 5

Yuqiu G.
Yuqiu G.

Reputation: 345

  • create/move the JSON file under folder assets

  • implement a method in the service

    private URL = './assets/navItems.json'; // ./ is important!
    
    constructor(private httpClient: HttpClient) {
    }
    
    fetch(): Observable<any> {
        return this.httpClient.get(this.URL);
    }
    
  • call it in component

    private navItems: NavItems[];
    
    constructor(private navItemsService: NavItemsService) { }
    
    ngOnInit(): void {
      this.publicationService.fetch().subscribe(navItems => this.navItems = navItems);
    }
    

Upvotes: 1

aRtoo
aRtoo

Reputation: 1892

If you are using Angular CLI: 7.3.3: In the assets folder, put fake JSON data and then on services, just do this:

const API_URL = './assets/data/db.json';

getAllPassengers(): Observable<PassengersInt[]> {
  return this.http.get<PassengersInt[]>(API_URL);
}

Enter image description here

Upvotes: 0

T04435
T04435

Reputation: 13992

I found that the simplest way to achieve this is by adding the file.json file under folder assets.

There isn't any need to edit file .angular-cli.json.

Service

@Injectable()
export class DataService {
  getJsonData(): Promise<any[]>{
    return this.http.get<any[]>('http://localhost:4200/assets/data.json').toPromise();
  }
}

Component

private data: any[];

constructor(private dataService: DataService) {}

ngOnInit() {
    data = [];
    this.dataService.getJsonData()
      .then( result => {
        console.log('ALL Data: ', result);
        data = result;
      })
      .catch( error => {
        console.log('Error Getting Data: ', error);
      });
  }

###Extra:

Ideally, you only want to have this in a development environment, so to be bulletproof, create a variable on your environment.ts file:

export const environment = {
  production: false,
  baseAPIUrl: 'http://localhost:4200/assets/data.json'
};

Then replace the URL on the http.get for ${environment.baseAPIUrl}.

And the environment.prod.ts file can have the production API URL.

Upvotes: 8

webta.st.ic
webta.st.ic

Reputation: 5169

My own solution

I created a new component called test in this folder:

Enter image description here

I also created a mock called test.json in the assets folder created by angular cli (important):

Enter image description here

This mock looks like this:

[
        {
            "id": 1,
            "name": "Item 1"
        },
        {
            "id": 2,
            "name": "Item 2"
        },
        {
            "id": 3,
            "name": "Item 3"
        }
]

In the controller of my component test, import follow rxjs like this:

import 'rxjs/add/operator/map'

This is important, because you have to map your response from the HTTP GET call, so you get JSON content and can loop it in your ngFor. Here is my code how I load the mock data. I used http get and called my path to the mock with this path this.http.get("/assets/mock/test/test.json"). After this I map the response and subscribe it. Then I assign it to my variable items and loop it with ngFor in my template. I also export the type. Here is my whole controller code:

import { Component, OnInit } from "@angular/core";
import { Http, Response } from "@angular/http";
import 'rxjs/add/operator/map'

export type Item = { id: number, name: string };

@Component({
  selector: "test",
  templateUrl: "./test.component.html",
  styleUrls: ["./test.component.scss"]
})
export class TestComponent implements OnInit {
  items: Array<Item>;

  constructor(private http: Http) {}

  ngOnInit() {
    this.http
      .get("/assets/mock/test/test.json")
      .map(data => data.json() as Array<Item>)
      .subscribe(data => {
        this.items = data;
        console.log(data);
      });
  }
}

And my loop in its template:

<div *ngFor="let item of items">
  {{item.name}}
</div>

It works as expected! I can now add more mock files in the assets folder and just change the path to get it as json. Notice that you have also to import the HTTP and Response in your controller. The same in you app.module.ts (main) like this:

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { HttpModule, JsonpModule } from '@angular/http';


import { AppComponent } from './app.component';
import { TestComponent } from './components/molecules/test/test.component';


@NgModule({
  declarations: [
    AppComponent,
    TestComponent
  ],
  imports: [
    BrowserModule,
    HttpModule,
    JsonpModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

Upvotes: 14

Supamiu
Supamiu

Reputation: 8731

You have to change

loadNavItems() {
    this.navItems = this.http.get("../data/navItems.json");
    console.log(this.navItems);
}

to

loadNavItems() {
    this.navItems = this.http.get("../data/navItems.json")
                    .map(res => res.json())
                    .do(data => console.log(data));
                    // This is optional. You can remove the last line
                    // if you don't want to log the loaded JSON file 
                    // in the console.
}

Because this.http.get returns an Observable<Response> and you don't want the response, you want its content.

The console.log shows you an observable, which is correct because navItems contains an Observable<Response>.

In order to get data properly in your template, you should use an async pipe.

<app-nav-item-comp *ngFor="let item of navItems | async" [item]="item"></app-nav-item-comp>

This should work well. For more information, please refer to the HTTP Client documentation.

Upvotes: 16

runit
runit

Reputation: 376

If you want to put the response of the request in the navItems. Because http.get() returns an observable, you will have to subscribe to it.

Look at this example:

// Version without map
this.http.get("../data/navItems.json")
    .subscribe((success) => {
      this.navItems = success.json();
    });

// With map
import 'rxjs/add/operator/map'
this.http.get("../data/navItems.json")
    .map((data) => {
      return data.json();
    })
    .subscribe((success) => {
      this.navItems = success;
    });

Upvotes: 0

EugenSunic
EugenSunic

Reputation: 13693

For Angular 5+, only perform steps 1 and 4


In order to access your file locally in Angular 2+ you should do the following (4 steps):

[1] Inside your assets folder create a .json file, example: data.json

[2] Go to your angular.cli.json (angular.json in Angular 6+) inside your project and inside the assets array put another object (after the package.json object) like this:

{ "glob": "data.json", "input": "./", "output": "./assets/" }

full example from angular.cli.json

"apps": [
    {
      "root": "src",
      "outDir": "dist",
      "assets": [
        "assets",
        "favicon.ico",
        { "glob": "package.json", "input": "../", "output": "./assets/" },
        { "glob": "data.json", "input": "./", "output": "./assets/" }
      ],

Remember, data.json is just the example file we've previously added in the assets folder (you can name your file whatever you want to)

[3] Try to access your file via localhost. It should be visible within this address, http://localhost:your_port/assets/data.json

If it's not visible then you've done something incorrectly. Make sure you can access it by typing it in the URL field in your browser before proceeding to step #4.

[4] Now preform a GET request to retrieve your .json file (you've got your full path .json URL and it should be simple)

 constructor(private http: HttpClient) {}
        // Make the HTTP request:
        this.http.get('http://localhost:port/assets/data.json')
                 .subscribe(data => console.log(data));

Upvotes: 97

Related Questions