使用角度 2 的 http.get() 从本地文件加载 json

Posted

技术标签:

【中文标题】使用角度 2 的 http.get() 从本地文件加载 json【英文标题】:Load json from local file with http.get() in angular 2 【发布时间】:2017-10-17 22:35:45 【问题描述】:

我正在尝试以角度 2 加载带有 http.get() 的本地 json。我尝试了一些东西,我在堆栈上找到了。它看起来像这样:

这是我的app.module.tsimportHttpModule 和来自@angular/httpJsonModule

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  

在我的组件中,我 import HttpResponse 来自 @angular/http。然后我有一个名为loadNavItems() 的函数,我尝试使用http.get() 加载带有相对路径的json,并使用console.log() 打印结果。函数在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);
    

我的本地 json 文件如下所示:

[
        "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"
    
]

控制台没有错误,我只是得到这个输出:

在我的 html 模板中,我想像这样循环这些项目:

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

我用我在堆栈上找到的解决方案做了这个,但我不知道为什么它不起作用?

编辑相对路径: 我的相对路径也有问题,但是当我使用../data/navItems.json 时,我确信它是正确的。在屏幕截图中,您可以看到 nav-comp.component.ts,我使用来自名为 data 的文件夹中的 json 文件的相对路径加载 json?怎么回事,控制台打印404错误,因为从相对路径找不到我的json文件?

【问题讨论】:

我找到了自己的解决方案并将其发布在下面(标记为正确答案)。再次感谢。 我有类似的问题,但有点不同。我在资产文件夹中有一张图片。我的服务中有一个File 类型的属性。我想将我资产中的图片读入File 类型的对象。您能帮忙实现这一点吗? 【参考方案1】:

对于 Angular 5+,仅预执行步骤 14


为了在 Angular 2+ 中本地访问您的文件,您应该执行以下操作(4 个步骤):

[1] 在您的资产文件夹中创建一个 .json 文件,例如:data.json

[2] 转到您的项目和 assets 中的 angular.cli.json(Angular 6+ 中的 angular.json) > 数组放置另一个对象(在 package.json 对象之后),如下所示:

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

来自 angular.cli.json 的完整示例

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

请记住,data.json 只是我们之前添加到 assets 文件夹中的示例文件(您可以随意命名文件)

[3] 尝试通过 localhost 访问您的文件。它应该在这个地址中可见,http://localhost:your_port/assets/data.json

如果它不可见,那么你做错了。确保您可以通过在浏览器的 URL 字段中键入它来访问它,然后再继续执行第 4 步。

[4] 现在执行 GET 请求以检索您的 .json 文件(您已经获得了完整路径 .json URL 和应该很简单)

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

【讨论】:

嗨 Eugen,我稍后会尝试,希望这有效!谢谢 我今天试一试并通知你。 @kingforever 你想把它放在哪里? assets 文件适用于此类场景。 在 Angular 5 中,您需要做的就是将 .json 文件放在 assets 文件夹下,如步骤 1 所述,并直接在服务调用中引用它,如步骤 4 所述。它有效对我来说。 这是一个非常巧妙的解决方案。感谢您的回答。【参考方案2】:

你必须改变

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

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.
    

因为this.http.get 返回一个Observable&lt;Response&gt; 而你不想要响应,你想要它的内容。

console.log 向您显示了一个 observable,这是正确的,因为 navItems 包含一个 Observable&lt;Response&gt;

为了在您的模板中正确获取数据,您应该使用async 管道。

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

这应该很好用,更多信息请参考HTTP Client documentation

【讨论】:

"Observable 类型上不存在属性映射" ? 我导入了“import 'rxjs/add/operator/map';”,错误没有了,但是控制台的输出是一样的? 在您的导入中添加import 'rxjs/add/operator/map';,或import Observable from 'rxjs'; 并将navItems: any 更改为navItems:Observable&lt;any&gt; @MrBuggy 如果您想对控制台进行输入,我可以编辑答案以添加一个,但我认为您的主要问题是在模板中呈现内容,所以我删除了控制台。记录。 让我们continue this discussion in chat.【参考方案3】:

我自己的解决方案

我在此文件夹中创建了一个名为 test 的新 component

我还在angular cli 创建的assests 文件夹中创建了一个名为test.json 的模拟(重要):

这个模拟看起来像这样:

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

在我的组件testimport的控制器中按照rxjs这样的方式

import 'rxjs/add/operator/map'

这很重要,因为您必须从 http get 调用中将 map response,因此您会得到一个 json 并可以在您的 ngFor 中循环它。这是我如何加载模拟数据的代码。我使用了httpget,并用这条路径this.http.get("/assets/mock/test/test.json") 调用了我的模拟路径。在此之后我map 响应和subscribe 它。然后我将它分配给我的变量items 并在我的template 中使用ngFor 循环它。我也导出类型。这是我的整个控制器代码:

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);
      );
  

我的循环是template

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

它按预期工作!我现在可以在assets 文件夹中添加更多模拟文件,只需更改路径以将其获取为json。请注意,您还必须在控制器中导入 HTTPResponse。你的 app.module.ts (main) 也是这样的:

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  

【讨论】:

.map(data => data.json() as Array) 这行告诉我 Object 没有方法 'json' @RanLottem 您是否正确导出类型“项目”? 无论我在这一行中转换的类型如何,data.json() 仍然会给出一个错误,即“对象”没有 json 属性。 默认get返回json,不需要做.json()【参考方案4】:

我发现 最简单 的方法是在文件夹下添加 file.jsonassets >。

无需编辑:.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);
      );
  

额外:

理想情况下,您只想在开发环境中使用它以防弹。在您的 environment.ts 上创建一个变量

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

然后将 http.get 上的 URL 替换为 $environment.baseAPIUrl

environment.prod.ts 可以有生产 API URL。

希望这会有所帮助!

【讨论】:

【参考方案5】:

将您的 navItems.json 放在“assets”文件夹中。 Angular 知道如何查看资产文件夹。所以而不是:

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

将路径改为简单:

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

【讨论】:

感谢 Philip 冷静的建议。它帮助了我 :-)【参考方案6】:assets下创建/移动json 在服务中实现方法
  private URL = './assets/navItems.json'; // ./ is important!

  constructor(private httpClient: HttpClient) 
  

  fetch(): Observable<any> 
      return this.httpClient.get(this.URL);
  
在组件中调用
  private navItems: NavItems[];

  constructor(private navItemsService: NavItemsService)  

  ngOnInit(): void 
    this.publicationService.fetch().subscribe(navItems => this.navItems = navItems);
  

【讨论】:

【参考方案7】:

我想将请求的响应放在navItems 中。因为http.get() 返回一个 observable,你必须订阅它。

看这个例子:

// 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;          
    );

【讨论】:

这是解决问题的另一种方法是的,我主要使用异步管道来避免使用变量来存储结果。此外,异步管道对我来说更好,因为它会为您取消订阅,这意味着如果您有跨页面持久的可观察对象(例如服务),您将避免内存泄漏。 我同意。这是解决和理解问题的更简单方法,但最后我会使用您的解决方案。 我找到了自己的解决方案并将其发布在下方(标记为正确答案)。再次感谢。【参考方案8】:

如果您使用Angular CLI: 7.3.3 我所做的是,在我的资产文件夹中,我将我的假 json 数据放在我的服务上,我只是这样做了。

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

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

【讨论】:

【参考方案9】:

尝试: this.navItems = this.http.get("data/navItems.json");

【讨论】:

以上是关于使用角度 2 的 http.get() 从本地文件加载 json的主要内容,如果未能解决你的问题,请参考以下文章

角度 $http.get / restangular 调用失败

如何使用 http get 从本地 Json 文件加载数据?

从角度12将类对象发送到asp.net core web api http get方法

如何从 jasmine 测试用例中解析角度 lang json 文件(角度本地化模块)

角度2如何从订阅返回数据

如何从flutter应用程序向本地主机发出http get请求?