Load json from local file with http.get() in angular 2

156,683

Solution 1

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 assests 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 a json 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 it's template:

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

It works as expected! I can now add more mock files in the assests 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 { }

Solution 2

For Angular 5+ only preform 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));

Solution 3

You have to change

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

for

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 loaded json in 
                        // 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 async pipe.

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

This should work well, for more informations, please refer to HTTP Client documentation

Solution 4

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

No need to edit: .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 dev environment so to be bulletproof. create a variable on your environment.ts

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 can have the production API URL.

Hope this helps!

Solution 5

Put your navItems.json in "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);
}
Share:
156,683
webta.st.ic
Author by

webta.st.ic

Senior Frontend Engineer at Merkle DACH, specialized in Frontend UI Engineering with HTML5, CSS3/SCSS, HandlebarsJS/Twig and JavaScript/JQuery. Also some experience in Frontend Application Engineering with Angular and TypeScript. DREAM. DO. DELIVER. Homepage - Merkle DACH | Jobs &amp; Careers Merkle DACH | Facebook - Merkle DACH | Twitter - Merkle DACH | Instagramm - Merkle DACH | LinkedIn - Merkle DACH LinkedIn - webta.st.ic

Updated on July 19, 2022

Comments

  • webta.st.ic
    webta.st.ic almost 2 years

    I'm trying to load a local json with http.get() in angular 2. I tried something, that I found here on stack. 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 with 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": "&Uuml;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 are no errors in the console, 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, but I have no idea why it doesn't 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 se the nav-comp.component.ts, where I load the json using relative path from the json file which is in the folder called data? What's wrong, the console prints an 404 error, because it can't find my json file from the relative path?

    enter image description here

  • webta.st.ic
    webta.st.ic about 7 years
    "Property map does not exist on type Observable<Response>" ?
  • webta.st.ic
    webta.st.ic about 7 years
    I imported "import 'rxjs/add/operator/map';", the error isn't there anymore but the output in the console is the same?
  • Supamiu
    Supamiu about 7 years
    add import 'rxjs/add/operator/map'; in your imports, or import {Observable} from 'rxjs'; and change navItems: any for navItems:Observable<any>
  • Supamiu
    Supamiu about 7 years
    @MrBuggy if you want to have an input to the console, I can edit the answer to add one, but I thought your main issue was to render the content in your template so I removed the console.log.
  • Supamiu
    Supamiu about 7 years
    @MrBuggy I added console.log to the observable chain using do oprtator, you can add it if you want to console.log received data.
  • webta.st.ic
    webta.st.ic about 7 years
    Now I got a problem with my relative path, but I'm pretty sure, that my path isn't wrong? Please look at my edited question?
  • Supamiu
    Supamiu about 7 years
    This is another way to solve the problem yes, I mainly use async pipe to avoid using variables just to store results. Also, async pipe is better to me because it will unsubscribe for you, meaning that you'll avoid memory leaks if you have observables that are persistent across pages (services for example).
  • Supamiu
    Supamiu about 7 years
  • runit
    runit about 7 years
    I agree. It's a easier way to solve and understand the problem but at the end I will you use your solution.
  • webta.st.ic
    webta.st.ic about 7 years
    This issue solves the path problem: github.com/angular/angular-cli/issues/1309
  • webta.st.ic
    webta.st.ic over 6 years
    Hi Eugen, I will try it later, hope this works! Thanks
  • webta.st.ic
    webta.st.ic over 6 years
    I will try it today and inform you.
  • webta.st.ic
    webta.st.ic over 6 years
    It seems to work. But my json stuff is in _body. Is this correct?
  • webta.st.ic
    webta.st.ic over 6 years
    And I can't loop the result in my ngFor, follow error: ERROR Error: Cannot find a differ supporting object '{ "items": [ { "id": 1, "name": "Home" }, { "id": 2, "name": "About us" }, { "id": 3, "name": "Contact" } ] } ' of type 'string'. NgFor only supports binding to
  • webta.st.ic
    webta.st.ic over 6 years
    I found my own solution and post it below (marked as correct answer). Thanks again.
  • webta.st.ic
    webta.st.ic over 6 years
    I found my own solution and post it below (marked as correct answer). Thanks again.
  • webta.st.ic
    webta.st.ic over 6 years
    I found my own solution and post it below (marked as correct answer). Thanks again.
  • Pratik Gandhi
    Pratik Gandhi over 6 years
    What if I don't want to put that file into assets?
  • EugenSunic
    EugenSunic about 6 years
    @kingforever where would you want to put it? assets file is intended for such scenarios.
  • Pratik Gandhi
    Pratik Gandhi about 6 years
    @eugne_sunic I have another data folder for my component where I want to put all my component level JSON files and I want to put only shared service's JSON files into asset folder.
  • Ran Lottem
    Ran Lottem about 6 years
    .map(data => data.json() as Array<Item>) This line tells me that Object does not have method 'json'
  • webta.st.ic
    webta.st.ic about 6 years
    @RanLottem Do you export the type "Item" correctly?
  • Ran Lottem
    Ran Lottem about 6 years
    Regardless of the type I cast into in this line, data.json() still gives an error that 'Object' doesn't have a json property.
  • Manoj Amalraj
    Manoj Amalraj about 6 years
    In Angular 5, all you need to do is to place the .json file under assets folder, as mentioned in step 1 and reference it directly in your service call, as mentioned in step 4. It works for me.
  • digthewells
    digthewells almost 6 years
    Mano is correct. In newer versions of Angular no need to change angular.json. Just put the json in assets and it will work. If someone could edit the answer with this that would be great. I didn't see this comment until after I started the steps above.
  • Arsen Khachaturyan
    Arsen Khachaturyan almost 6 years
    I don't think that assets are the only way of reading local file adding, see my answer here: stackoverflow.com/a/50940939/806202
  • Sam Vloeberghs
    Sam Vloeberghs about 5 years
    the default get returns json, no need to do .json()
  • Lalit Narayan Mishra
    Lalit Narayan Mishra about 5 years
    That's a pretty neat solution. Thanks for the answer.
  • Kieran Ryan
    Kieran Ryan over 2 years
    Thanks Philip for your calm advice.. it helped me out :-)