Отображение объекта JSON в наблюдаемый для использования с ngFor Angular
Я пытаюсь сопоставить объект JSON наблюдаемому интерфейсу, который я настроил в своем угловом приложении, я надеюсь, что после его сопоставления я смогу использовать его как вход для циклического просмотра ngFor.
К сожалению, я не верю, что я правильно настраиваю свою службу или, возможно, вызов службы.
Я получаю объект json, возвращаемый как один объект, но ngFor не выполняет должным образом циклический просмотр возвращаемых результатов, любая помощь в указании того, что я могу пропустить, будет принята с благодарностью.
// Интерфейс, к которому я пытаюсь получить доступ
export interface IProduct {
name: string;
description: string;
price: number;
category: string;
image: string;
}
// Служба, которую я пытаюсь вызвать
private productList = new BehaviorSubject<IProduct[]|null>(null);
productListChanges$ = this.productList.asObservable();
constructor(private http: HttpClient) { }
getProds(): Observable<IProduct[]> {
this.productList.next(null);
return this.http.get<IProduct[]>
('http://localhost:4200/assets/data/products.json')
.pipe(
tap(data => this.productList.next(data)),
);
}
// Позвонить на сервис
productsList: IProduct[] = [];
this.productService.getProds().subscribe((response: any) => {
this.productsList = response.products[0] as IProduct[];
console.log(this.productsList);
});
// Попытка использовать ngFor с полученным объектом
<app-product *ngFor="let product of productsList" [prod]="product" ></app-product>
// Журнал консоли из сервисного вызова выводит следующее
3 ответа
Попробуйте с асинхронным циклом с Observables.
<app-product *ngFor="let product of productsList | async" [prod]="product" ></app-product>
Как показывает вывод вашей консоли, productsList
это объект, но ngFor
ожидает массив.
Если вы можете изменить данные, это должно быть легко выполнимо изменить на массив ([...]
) вместо объекта ({...}
).
В противном случае у вас есть несколько вариантов преобразования структуры в коде в массив. Например, при использовании Object.values()
Вы можете преобразовать вашу текущую структуру в массив. Кроме того, вы также можете использовать KeyValuePipe, доступную начиная с Angular 6.1. Также ответили здесь /questions/4569272/klyuch-dostupa-i-znachenie-obekta-ispolzuya-ngfor/4569286#4569286
Я вижу, что вы используете HTTP для обслуживания данных JSON, которые легко доступны как данные, поступающие из статического файла, существующего в вашей папке ресурсов. Я бы избегал HTTP-звонков для их обслуживания. Я реорганизовал ваш код как для обслуживания статических данных, так и для поддержки удаленного запроса данных с использованием одного и того же метода обслуживания. Это также должно помочь во время модульного тестирования, поскольку асинхронное тестирование - это кошмар.
// Changed the Interface to a class
export class Product {
name: string;
description: string;
price: number;
category: string;
image: string;
}
// Create a sample-data.ts file
export const ProductListData: Array<Product> = [
{
name: 'ProductName',
description: 'Description',
price: '9.99', // Maybe should be a number type and not string
category: 'Test Category',
image: 'your url for testing'
}
]
// In service...
import { of } from 'rxjs';
import { ProductListData } from './sample-data';
useSampleData = false;
getProducts(): Observable<Array<Product>> {
if (useSampleData) {
// Use this is your want to serve static JSON
return of(ProductListData); // of() turns your readily avialable object into an obeservable promise
} else {
// Get from actual HTTP as async
return this.http.get<Array<Product>>('http://localhost:4200/api/your-endpoint-url');
}
}
// In you Component...
public productList: Array<Product> = [];
this.productService.getProducts().subscribe(
productList => {
this.productsList = productList;
},
err => {
console.log('Error: ', err);
}
);
Ваш шаблон не нуждается в изменении.