Angular 18 @для возврата ОШИБКИ TypeError: newCollection[Symbol.iterator] не является функцией

Я решил начать работать с последней версией 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
        }
    }
}

пожалуйста, поделитесь ответом API

Naren Murali 23.07.2024 13:44

Используйте track movie.id, «дорожка» предназначена для уникального «ключа». ПРИМЕЧАНИЕ 1: похоже, что в «this.movies» у вас нет массива. ПРИМЕЧАНИЕ 2: обычно для определения интерфейса или класса используется PascalCase, лучше «интерфейсный фильм», чем интерфейсный фильм».

Eliseo 23.07.2024 13:47

@NarenMurali Я обновил вопрос ответом API

weinde 23.07.2024 13:48
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
1
3
83
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Вы также можете добавить интерфейсы для ответа, поступающего от 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 23.07.2024 13:52

@weinde попробуйте мой обновленный ответ с интерфейсами для ответа.

Naren Murali 23.07.2024 13:53

В какой файл мне поместить первую часть вашего кода (интерфейсы)?

weinde 23.07.2024 13:57

@weinde лучше использовать отдельные файлы, чтобы код был организован, каждый интерфейс - отдельный файл с <<interfacename>>.model.ts

Naren Murali 23.07.2024 13:58

Да, я сделал это, но теперь получаю сообщение TS2304: Невозможно найти имя «GetMoviesResponse». src/app/movielist/movielist.comComponent.ts:26:13: 26 │ (данные: GetMoviesResponse) => { ╵

weinde 23.07.2024 14:00

@weinde Вам нужно импортировать его из файла, попробуйте навести курсор на ошибку и импортировать ее в разделе быстрых исправлений\

Naren Murali 23.07.2024 14:01

Давайте продолжим обсуждение в чате.

weinde 23.07.2024 14:06

Вам нужен доступ к свойству 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>

Другие вопросы по теме