Не удается прочитать свойство для каждого неопределенного - PullRequest
0 голосов
/ 14 июня 2019

Название этого вопроса - просто ошибка, которую я сейчас получаю, но мне действительно нужна помощь в понимании наблюдаемых и вызовов API. По какой-то причине я просто не смог хорошо понять эту концепцию, и я надеюсь, что у кого-то может быть объяснение, которое наконец-то щелкнет.

Я пытаюсь создать новый сервис Angular, который извлекает JSON из API. Затем мне нужно сопоставить ответ с моделью. Из-за странных соглашений об именах, описания работ и требования к работе здесь взаимозаменяемы. Вот мой класс обслуживания.

import { CommunicationService } from './communication.service';
import { AiDescription } from '../models/ai-description.model';
import { Observable } from 'rxjs/Observable';
import { BehaviorSubject } from 'rxjs/BehaviorSubject';


@Injectable()
export class AiDescriptionService {

    requirements: Observable<AiDescription[]>;
    private aiDescriptionUrl: string = '/api/core/company/jobdescriptions';
    private dataStore: {
        requirements: AiDescription[]
    };
    private _requirements: BehaviorSubject<AiDescription[]>;
    private emptyRequestParams = {
        "company_id": "",
        "carotene_id": "",
        "carotene_version": "",
        "city": "",
        "state": "",
        "country": ""
    };

    readonly caroteneVersion: string = "caroteneV3";

    constructor(
        private communicationService: CommunicationService
    ) {
        this.dataStore = { requirements: [] };
        this._requirements = new BehaviorSubject<AiDescription[]>([]);
        this.requirements = this._requirements.asObservable();
    }

    LoadRequirements(params: Object) {
        this.communicationService.postData(this.aiDescriptionUrl, params)
        .subscribe(res => {
            let jobDescriptions = [];
            jobDescriptions = res.jobdescriptions;
            jobDescriptions.forEach((desc: { id: string; description: string; }) => {
                let aiDescription = new AiDescription();
                aiDescription.id = desc.id;
                aiDescription.description = desc.description;
            });
            this.dataStore.requirements = res;
            this._requirements.next(Object.assign({}, this.dataStore).requirements);
        });
    }

    CreateRequest(
        companyID : string,
        caroteneID : string,
        city: string,
        state: string,
        country: string
    ): Object {
        let newRequestParams = this.emptyRequestParams;
        newRequestParams.company_id = companyID;
        newRequestParams.carotene_id = caroteneID;
        newRequestParams.carotene_version = this.caroteneVersion;
        newRequestParams.city = city;
        newRequestParams.state = state;
        newRequestParams.country = country;
        this.LoadRequirements(newRequestParams);
        return this.dataStore;
    }

}

Функция postData (), вызываемая this.communicationService, находится здесь:

  postData(url: string, jobInformation: any): Observable<any> {
    const start = new Date();
    const headers = new HttpHeaders({ 'Content-Type': 'application/json' });
    const body = JSON.stringify(jobInformation);
    const options = { headers };

    return this.http.post(url, body, options)
      .catch(err => Observable.throw(err))
      .do(() => {
        this.analyticsLoggingService.TrackTiming('JobPostingService', 'PostSuccess', new Date().getTime() - start.getTime());
      }, () => {
        this.analyticsLoggingService.TrackError('JobPostingService', 'PostFailure');
      });
  }

Я не написал функцию postData и не смог бы ее изменить. При запуске модульного теста, я получаю эту ошибку: «Ошибка типа: Не удается прочитать свойство« forEach »неопределенного».

Но больше, чем просто исправление ошибки, я действительно пытаюсь лучше понять использование Observables, что я не смог понять из других источников.

1 Ответ

0 голосов
/ 14 июня 2019

В вашем примере я рекомендую заменить any и Object на явно определенные модели.

Вот пример Angular 8 для вызовов API подписки, обещания и Observable. Вы можете получить больше информации здесь: https://angular.io/tutorial/toh-pt6.

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

import { User } from './user.model';

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

    users: User[];

    authHeaders = new HttpHeaders()
        .set('Content-Type', 'application/json');

    constructor(
        private readonly http: HttpClient
    ) { }

    getUsers() {
        this.http.get(`https://myApi/users`, { headers: this.authHeaders })
            .subscribe(
                (data: User[]) => {
                    this.users = data;
                }, (error: HttpErrorResponse) => { /* handle error */ });
    }

    async getUserPromise(userID: number): Promise<User> {

        const url = `https://myApi/users/${userID}`;

        return this.http.get<User>(url, { headers: this.authHeaders })
            .toPromise();
    }

    getUserObservable(userID: number): Observable<User> {

        const url = `https://myApi/users/${userID}`;

        return this.http.get<User>(url, { headers: this.authHeaders });
    }

}

Мне нравится хранить модели классов в отдельных файлах. Этот пример будет иметь user.model.ts с содержанием вроде:

export class User {
    constructor(
        public id: number,
        public username: string,
        public displayName: string,
        public email: string
    ) { }
}

Я не включил заголовки аутентификации или обработку ошибок для краткости; однако вы можете добавить их по мере необходимости.

...