json - Veriyi Angular Material Veri Tablosuna bağlamak mümkün değil


Sorun

JSON verilerini bir Angular Material veri tablosuna bağlarken bir sorun yaşıyorum.

Arka Plan

Kullanıcılara film bilgisi sağlamak amacıyla tasarlanmış küçük bir uygulama geliştiriyorum. Kullanıcı bir arama başlattığında bir API çağrısı tetiklenir. Bu daha sonra yanıt verilerini veri tablosunu doldurmalıdır.

API çağrısını başarıyla yapabilsem de, veri tablosuna hiçbir veri iletilmiyor:

Geliştirici Araçlarında API Yanıtı

Ayrıca, konsolda herhangi bir hata görünmüyor ve tabloyu test verileriyle doldurabiliyorum.

İşte kod:

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

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 (container sınıfında belirtilen arama işlevi başka bir bileşende ele alınır)

<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

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

Cevap #1

API tarafından döndürülen JSON aşağıdaki şekildedir

{
  "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.
  ]
} 

Bu nedenle bazı ayarlamalar yapmanız gerekiyor.

Öncelikle, yanıtı projekte etmeniz ve filmler dizisini içeren Search özelliğini çıkarmanız gerekir. Bu, servisinizde yapılmalıdır (tiplerin geliştirilmiş kullanımına dikkat edin)

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

O zaman cevaptaki filmlerin şeklini doğru şekilde tanımlamak için model arayüzünde özellik adlarını belirtmemiz gerekiyor

film.model.ts

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

Şimdi türleri biraz geliştirmek için bileşenin kendisini ayarlayalım

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

Kolonların isimlerini kısıtlamak için tiplerin kullanımının nasıl iyileştirildiğine ve bileşen ile servis arasındaki senkronizasyonun nasıl sağlandığına dikkat edin. Ayrıca, servis yönteminin geliştirilmiş tip imzasından akan tip çıkarımından faydalanmak için gereksiz tip bilgilerinin nasıl iyileştirildiğine de dikkat edin.