Я решил начать работать с последней версией Angular (Angular 18.1), пока работал с версиями с 7 по 14...
Я только что попробовал создать небольшое приложение для демонстрации списка фильмов...
Я создал действительно простой сервис, который получает некоторые данные из API и отображает эти данные в списке в формате html...
Я решил использовать новый синтаксис @for из последней версии Angular, но теперь получаю следующую ошибку: ERROR TypeError: newCollection[Symbol.iterator] is not a function
Связано ли это с новой версией nagular или я слеп и не заметил проблемы в своем коде?
Обновлено: Console.log работает.
Вот код компонента.ts:
export class MovielistComponent implements OnInit{
movies: movie[] = [];
constructor(
private movieService: GetMoviesService,
) { }
ngOnInit() {
this.getMoviesList();
}
getMoviesList() {
this.movieService.getMovies().subscribe(
data => {
this.movies = data;
console.info('Movies: ', this.movies);
}
)
}
}
Вот код html-файла:
<ul>
@for (movie of movies; track movie.attributes) {
<li>{{ movie.attributes.name }}</li>
} @empty {
<li>There are no items.</li>
}
</ul>
А вот код model.ts:
export interface movie {
id: number,
attributes: {
name: string,
imageUrl: string,
synopsis: string,
year: string,
genre: string,
}
}
По запросу вот ответ API:
{
"data": [
{
"id": 1,
"attributes": {
"name": "The Shawshank Redemption",
"imageUrl": "https://m.media-amazon.com/images/M/MV5BNDE3ODcxYzMtY2YzZC00NmNlLWJiNDMtZDViZWM2MzIxZDYwXkEyXkFqcGdeQXVyNjAwNDUxODI@._V1_FMjpg_UY1800_.jpg",
"synopsis": "Over the course of several years, two convicts form a friendship, seeking consolation and, eventually, redemption through basic compassion.",
"year": "1994",
"genre": "drama",
"createdAt": "2024-07-16T12:34:06.769Z",
"updatedAt": "2024-07-16T12:36:29.952Z",
"publishedAt": "2024-07-16T12:36:29.951Z"
}
},
{
"id": 2,
"attributes": {
"name": "The Godfather",
"imageUrl": "https://m.media-amazon.com/images/M/MV5BM2MyNjYxNmUtYTAwNi00MTYxLWJmNWYtYzZlODY3ZTk3OTFlXkEyXkFqcGdeQXVyNzkwMjQ5NzM@._V1_FMjpg_UY1982_.jpg",
"synopsis": "Don Vito Corleone, head of a mafia family, decides to hand over his empire to his youngest son, Michael. However, his decision unintentionally puts the lives of his loved ones in grave danger.",
"year": "1972",
"genre": "crime, drama",
"createdAt": "2024-07-16T12:36:14.143Z",
"updatedAt": "2024-07-16T12:36:15.723Z",
"publishedAt": "2024-07-16T12:36:15.720Z"
}
},
{
"id": 3,
"attributes": {
"name": "The Dark Knight",
"imageUrl": "https://m.media-amazon.com/images/M/MV5BMTMxNTMwODM0NF5BMl5BanBnXkFtZTcwODAyMTk2Mw@@._V1_FMjpg_UY2048_.jpg",
"synopsis": "When the menace known as the Joker wreaks havoc and chaos on the people of Gotham, Batman must accept one of the greatest psychological and physical tests of his ability to fight injustice.",
"year": "2008",
"genre": "action, crime, drama, thriller",
"createdAt": "2024-07-22T09:37:42.564Z",
"updatedAt": "2024-07-22T09:38:19.346Z",
"publishedAt": "2024-07-22T09:38:19.343Z"
}
}
],
"meta": {
"pagination": {
"page": 1,
"pageSize": 25,
"pageCount": 1,
"total": 3
}
}
}
Используйте track movie.id
, «дорожка» предназначена для уникального «ключа». ПРИМЕЧАНИЕ 1: похоже, что в «this.movies» у вас нет массива. ПРИМЕЧАНИЕ 2: обычно для определения интерфейса или класса используется PascalCase, лучше «интерфейсный фильм», чем интерфейсный фильм».
@NarenMurali Я обновил вопрос ответом API
Вы также можете добавить интерфейсы для ответа, поступающего от API.
export interface Pagination{
page: number;
pageSize: number;
pageCount: number;
total: number;
}
export interface GetMoviesResponse {
data: movie[];
meta: Pagination;
}
Вам необходимо получить доступ к свойству data
внутри ответа, который представляет собой массив.
Обычно мы получаем эту ошибку, когда пытаемся использовать объект в ngFor или @for ERROR TypeError: newCollection[Symbol.iterator] is not a function
export class MovielistComponent implements OnInit{
movies: movie[] = [];
constructor(
private movieService: GetMoviesService,
) { }
ngOnInit() {
this.getMoviesList();
}
getMoviesList() {
this.movieService.getMovies().subscribe(
(data: GetMoviesResponse) => {
this.movies = data.data; // changed here!
console.info('Movies: ', this.movies);
}
)
}
}
Теперь я получаю следующее: [ОШИБКА] TS7015: Элемент неявно имеет тип «любой», поскольку индексное выражение не имеет типа «число». [плагин angular-compiler] src/app/movielist/movielist.comComponent.ts:27:27: 27 │ this.movies = data['data']; // здесь изменилось! ╵ ~~~~~~
@weinde попробуйте мой обновленный ответ с интерфейсами для ответа.
В какой файл мне поместить первую часть вашего кода (интерфейсы)?
@weinde лучше использовать отдельные файлы, чтобы код был организован, каждый интерфейс - отдельный файл с <<interfacename>>.model.ts
Да, я сделал это, но теперь получаю сообщение TS2304: Невозможно найти имя «GetMoviesResponse». src/app/movielist/movielist.comComponent.ts:26:13: 26 │ (данные: GetMoviesResponse) => { ╵
@weinde Вам нужно импортировать его из файла, попробуйте навести курсор на ошибку и импортировать ее в разделе быстрых исправлений\
Давайте продолжим обсуждение в чате.
Вам нужен доступ к свойству data
. Вы переименовываете аргумент subscribe
в response
, чтобы понять разницу.
Также вы не можете использовать inject
вместо constructor
для внедрения сервиса. Также вам следует unsubscribe
подписчику`
export class MovielistComponent implements OnInit {
movies: movie[] = [];
private destroyRef = inject(DestroyRef);
private movieService = inject(GetMoviesService)
ngOnInit() {
this.getMoviesList();
}
getMoviesList() {
this.movieService.getMovies().pipe(takeUntilDestroyed(this.destroyRef)).subscribe(
(response:{[key:string]:value}) => {
this.movies: = response['data'] || [];
console.info('Movies: ', this.movies);
}
)
}
}
<ul>
@for (movie of movies; track movie.id) {
<li>{{ movie.attributes.name }}</li>
} @empty {
<li>There are no items.</li>
}
</ul>
пожалуйста, поделитесь ответом API