简体   繁体   English

无法将数据绑定到角度材料数据表

[英]Unable to bind data to Angular Material Data Table

Issue问题

I'm having an issue binding JSON data to an Angular Material data table.我在将 JSON 数据绑定到 Angular Material 数据表时遇到问题。

Background背景

I'm developing a small application which is designed to provide users with film information.我正在开发一个小应用程序,旨在为用户提供电影信息。 An API call is initiated following the user triggering a search.在用户触发搜索后启动 API 调用。 This should then populate the data table with the response data.然后应该用响应数据填充数据表。

Whilst I can successfully make the API call, no data is passed into the data table:虽然我可以成功进行 API 调用,但没有数据传递到数据表中:

API Response in Dev Tools开发工具中的 API 响应

Furthermore, no errors are shown in the console and I can populate the table with test data.此外,控制台中没有显示任何错误,我可以用测试数据填充表。

Here is the code:这是代码:

api-calls.service.ts api-calls.service.ts

import { Injectable } from '@angular/core';
import { HttpClient, HttpResponse } from '@angular/common/http';
import { Observable, of } from 'rxjs';

@Injectable()
export class ApiService {
constructor(private http:HttpClient){}

public getFilms(searchTerm): Observable<any> {
  const apiUrl = 'http://www.omdbapi.com/?apikey=b1464edd&s=';
  const fullLink = apiUrl + searchTerm
  return this.http.get(fullLink)
}}

app.component.ts app.component.ts

import { Component, OnInit } from '@angular/core';
import { Films } from './models/films.model';
import { ApiService } from './services/api-calls.service';
import { MatTableDataSource } from '@angular/material';
@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})

export class AppComponent implements OnInit{

constructor(private apiService:ApiService) {}

displayedColumns: string[] = ['title', 'year', 'imdbID', 'poster', 'type']
dataSource: MatTableDataSource<any[]>;
searchTerm = '';

handleSearch(event) {
  if(event.action === 'SEARCH') {
    this.searchTerm = event.query
    this.apiService.getFilms(this.searchTerm).subscribe(
      data => this.dataSource = new MatTableDataSource<Films[]>(data)
    )}
  }

  ngOnInit() {
  }
}

app.component.html (the search function outlined in the container class is handled in another component) app.component.html(容器类中概述的搜索功能在另一个组件中处理)

<div class = "container">
      <mat-card>
          <h2>Lightweight IMDb Search Engine</h2>
          <app-search (searchEvent)="handleSearch($event)"></app-search>
      </mat-card>

      <div>
        <mat-table [dataSource] = "dataSource">
          <ng-container matColumnDef="title">
            <mat-header-cell *matHeaderCellDef> Title </mat-header-cell>
            <mat-cell *matCellDef="let films"> {{ films.title }}</mat-cell>
          </ng-container>
          <ng-container matColumnDef="year">
            <mat-header-cell *matHeaderCellDef> Year </mat-header-cell>
            <mat-cell *matCellDef="let films"> {{ films.year }}</mat-cell>
          </ng-container>
          <ng-container matColumnDef="imdbID">
            <mat-header-cell *matHeaderCellDef> imdbID </mat-header-cell>
            <mat-cell *matCellDef="let films"> {{ films.imdbID }}</mat-cell>
          </ng-container>
          <ng-container matColumnDef="poster">
            <mat-header-cell *matHeaderCellDef> Poster </mat-header-cell>
            <mat-cell *matCellDef="let films"> {{ films.poster }}</mat-cell>
          </ng-container>
          <ng-container matColumnDef="type">
            <mat-header-cell *matHeaderCellDef> Type </mat-header-cell>
            <mat-cell *matCellDef="let films"> {{ films.type }}</mat-cell>
          </ng-container>
          <mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
          <mat-row *matRowDef="let row; columns: displayedColumns"></mat-row>
        </mat-table>
      </div>
  </div>

film.model.ts电影.model.ts

export interface Films {
    title: string;
    year: string;
    imdbID: string;
    poster: string;
    type: string;
}

The JSON returned by the API has the following shape API 返回的 JSON 具有以下形状

{
  "Search": [
    {"Title":"Hello, My Name Is Doris","Year":"2015","imdbID":"tt3766394","Type":"movie","Poster":"https://m.media-amazon.com/images/M/MV5BMTg0NTM3MTI1MF5BMl5BanBnXkFtZTgwMTAzNTAzNzE@._V1_SX300.jpg"},
    // etc.
  ]
} 

Therefore you need to make some adjustments.因此,您需要进行一些调整。

Firstly, you need to project the response, extracting the Search property which contains the array of films.首先,您需要投影响应,提取包含电影数组的Search属性。 This should be done in your service (note the improved use of types)这应该在您的服务中完成(注意类型的改进使用)

api-calls.service.ts api-calls.service.ts

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';

import Film from './models/film.model';

@Injectable()
export class ApiService {
  constructor(private http:HttpClient){}

  getFilms(searchTerm): Observable<Film[]> {
    const apiUrl = 'http://www.omdbapi.com/?apikey=b1464edd&s=';
    const fullLink = apiUrl + searchTerm;
    type Response = { Search: Film[] };
    return this.http.get<Response> (fullLink)
      .pipe(map(response => response.Search));
  }
}

Then we need to declare the property names in the model interface to correctly describe the shape of the films in the response然后我们需要在模型界面中声明属性名称,以正确描述响应中的薄膜形状

film.model.ts电影.model.ts

export default interface Film {
    Title: string;
    Year: string;
    imdbID: string;
    Poster: string;
    Type: string;
}

Now let's adjust the component itself to improve the types a bit现在让我们调整组件本身以稍微改进类型

app.component.ts app.component.ts

import { Component } from '@angular/core';
import { ApiService } from './services/api-calls.service';
import { MatTableDataSource } from '@angular/material';

import Film from './models/film.model';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})

export class AppComponent {

  constructor(private apiService:ApiService) {}

  displayedColumns: (keyof Film)[] = ['Title', 'Year', 'imdbID', 'Poster', 'Type'];
  dataSource?: MatTableDataSource<Film[]>;
  searchTerm = '';

  handleSearch({ action, query }) {
    if (action === 'SEARCH' && query) {
      this.searchTerm = query;
      this.apiService.getFilms(this.searchTerm)
        .subscribe(films => this.dataSource = new MatTableDataSource(films));
    }
  }
}

Note how the use of types has been improved to constrain the names of the columns, that they stay in sync between the component and the service.请注意如何改进类型的使用以限制列的名称,使它们在组件和服务之间保持同步。 Also note that redundant type information has been improved to take advantage of the type inference flowing from the improved type signature of the service method.另请注意,冗余类型信息已得到改进,以利用来自服务方法的改进类型签名的类型推断。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM