angular/typescript - 我如何从 url 内部数组中获取项目列表

angular/typescript - how can i get a list of items from an url inside array

我正在研究 SWAPI API 和 angular,我想知道如何获得 html 上的星舰名称列表。我可以从 api 和 URL 列表中获取人名列表,但星舰在数组中的 url 中。我怎样才能访问它们?

我有一个 stackblitz link 一些工作:

https://stackblitz.com/edit/angular-ivy-3cqfsb?file=src/app/app.component.html

通过在模板中使用 async 管道,我们可以像这样在模板中完成大部分工作:

<div *ngIf="data$ | async as data">
  <div class="boxes">
    <div class="box" *ngFor="let person of data.results">
      <p>
        <strong>name: </strong>
        <br />
        {{ person.name }}
      </p>
      <p><strong>Starships:</strong></p>
      <ul>
        <li *ngFor="let ship of person.starships">{{ ship.name }}</li>
      </ul>
    </div>
  </div>
  <div class="buttons">
    <button name="previous" (click)="pagination(data.previous)">
      previous
    </button>
    <button name="next" (click)="pagination(data.next)">next</button>
  </div>
</div>

接下来您将使用组件作为中间人在模板和服务之间进行通信:

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css'],
})
export class AppComponent {
  // Using a template pipe, unsubscribe will happen automatically 
  data$ = this.peopleService.data$;

  constructor(private peopleService: peopleService) {}

  pagination(url: string) {
    this.peopleService.go(url);
  }
}

接下来在服务中我们定义一个 data 行为主体,它将包含要加载的初始 url。

我创建了两个 observables ships$person$ 两个 observables ships$person$ 将通过每个人并将那个人传递给 ships$.

@Injectable({ providedIn: 'root' })
export class peopleService {

  private readonly rootURL = 'https://swapi.dev/api/people/';

  ships$ = (person: Person) =>
    of(person.starships).pipe(
      // Since i is an array each item will be returned to the next function
      concatMap((i: string[]) => i),
      // i is now a string from the previous function
      concatMap((i) => this.http.get(i)),
      // Once all urls complete convert the result back to an array
      toArray<Starship>(),
      // Replace the string version of the array with the object version
      tap((i) => (person.starships = i)),
      // Pass person on to the next function
      map(() => person)
    );

  people$ = (people: Person[]) =>
    of(people).pipe(
      // Read each array item as a string and pass it to the next function
      concatMap((i) => i),
      // i is now a Person object we will pass it to ships
      concatMap((i) => this.ships$(i)),
      // convert the results back to an array
      toArray()
    );

  data = new BehaviorSubject<string>(this.rootURL);
  data$ = this.data.pipe(
    // Process the value of the behavior subject
    concatMap((url) => this.http.get<Results>(url)),
    concatMap((result) =>
      // Send the results to the people func for processing
      this.people$(result.results).pipe(
        // Map back to the original with strings replace by objects
        map<any, Results<Starship>>(() => <Results<Starship>>result)
      )
    )
  );

  constructor(private http: HttpClient) { }

  go(url?: string) {
    // This will trigger the `data` pipe to run again
    this.data.next(url || this.rootURL);
  }
}

这里有一些使用的例子 interfaces

interface Results<T = string | Starship> {
  next: string;
  previous: string;
  results: Person<T>[];
}

interface Person<T = string | Starship> {
  name: string;
  starships: T[];
}

interface Starship {
  name: string;
}

工作示例:https://stackblitz.com/edit/Whosebug-starwars-http