Угловая ошибка - NgFor поддерживает привязку только к Iterables, таким как массивы

Я создаю приложение Angular с серверной частью Node. Вот мои соответствующие части server.js с конечными точками REST:

var express = require('express');
var app = express();
var bodyParser = require('body-parser');
var cors = require('cors');
var mysql = require('mysql');

const con = mysql.createConnection({
    host: 'localhost',
    user: 'myusername',
    password: 'mypass',
    database: 'somedb'
});

con.connect((err) => {
    if (err) throw err;
    console.info('Connected!');
});

app.use(bodyParser.json());
app.use(cors());

app.route('/api/levels').get((req, res) => {
    con.query('SELECT * FROM level', (err, rows) => {
        if (err)
            res.send(JSON.stringify({ "status": 500, "error": err, "response": null }));
        else
            res.send(JSON.stringify({ "status": 200, "error": null, "response": rows }));
    });
});
...

Эта часть работает, я протестировал ее через Postman и получил следующий ответ:

{
    "status": 200,
    "error": null,
    "response": [
        {
            "id": 1,
            "title": "A1.1"
        },
        {
            "id": 2,
            "title": "A1.2"
        },
        ... // the rest of the rows
    ]
}

Угловой сервис:

@Injectable()
export class LevelService {

  constructor(private http: HttpClient) {}

  public getAll() {
    return this.http.get('http://localhost:8000/api/levels/');
  }
  ...
}

Служба вызывается в компоненте:

@Component({
  selector: 'app-level-list',
  templateUrl: './level-list.component.html',
  styleUrls: ['./level-list.component.css']
})
export class LevelListComponent implements OnInit {
  private levels: any[];

  constructor(private levelService: LevelService) { }

  ngOnInit() {
    this.levelService.getAll().subscribe((data: any[]) => this.levels = data);
  }
}

Данные используются в шаблоне компонента:

<ul class = "level-list">
  <li *ngFor = "let level of levels">
    <app-level-list-item [level] = "level">
    </app-level-list-item>
  </li>
</ul>

И, наконец, он должен отображаться на главной странице:

<div style = "text-align:center">
  <h1>{{ title }}</h1>
</div>
<p>{{introText}}</p>
<app-level-list></app-level-list>

Однако, когда я открываю страницу, данные не отображаются, а в консоли появляется ошибка:

ERROR Error: Cannot find a differ supporting object '[object Object]' of type 'object'.
NgFor only supports binding to Iterables such as Arrays.

Что я делаю неправильно?

Я думаю, что ваши уровни не являются массивом, или у вас есть ошибка при разборе ответа, попробуйте отобразить this.levels

Fateh Mohamed 04.04.2018 18:23

Попробуйте это: (data: any []) => this.levels = data.response

Alexander Poshtaruk 04.04.2018 18:25
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Angular и React для вашего проекта веб-разработки?
Angular и React для вашего проекта веб-разработки?
Когда дело доходит до веб-разработки, выбор правильного front-end фреймворка имеет решающее значение. Angular и React - два самых популярных...
Эпизод 23/17: Twitter Space о будущем Angular, Tiny Conf
Эпизод 23/17: Twitter Space о будущем Angular, Tiny Conf
Мы провели Twitter Space, обсудив несколько проблем, связанных с последними дополнениями в Angular. Также прошла Angular Tiny Conf с 25 докладами.
Угловой продивер
Угловой продивер
Оригинал этой статьи на турецком языке. ChatGPT используется только для перевода на английский язык.
Мое недавнее углубление в Angular
Мое недавнее углубление в Angular
Недавно я провел некоторое время, изучая фреймворк Angular, и я хотел поделиться своим опытом со всеми вами. Как человек, который любит глубоко...
Освоение Observables и Subjects в Rxjs:
Освоение Observables и Subjects в Rxjs:
Давайте начнем с основ и постепенно перейдем к более продвинутым концепциям в RxJS в Angular
0
2
353
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

Это не похоже на то, что ваш ответ службы является типом массива, а скорее:

interface ServiceResponse {
    status: number;
    error: any; // not apparent of the type
    response: Level[];
}

Я думаю, что вам нужно изменить свой метод getAll, чтобы отобразить его, чтобы ответ был вашим Level[] вместо ServiceResponse:

public getAll(): Observable<Level[]> {
    return this.http.get<ServiceResponse>('http://localhost:8000/api/levels/')
        .map(res => res.response);
}

Дать согласие. Мне кажется, причина в этом.

Hugo Noro 04.04.2018 19:40
Ответ принят как подходящий

HTTP-запрос возвращает вам тип ответа, и фактические данные, которые вы отправили, находятся в его теле. Чтобы получить его, используйте метод .json (), и после этого вы можете получить доступ к своему массиву, например к свойству, как ребята, упомянутые выше.

this.levelService.getAll().subscribe(data => this.levels = data.json().response);

ОБНОВИТЬ

Оказывается, нет необходимости использовать .json () для HttpClient (на самом деле, я думал о Http, когда писал это) Так что ты можешь просто написать

this.levelService.getAll().subscribe(data => this.levels = data['response']);

И, по всей видимости, использование скобок требуется в соответствии с документацией.

Это неправильно. HttpClient больше не требует вызова .json ()

Hugo Noro 04.04.2018 19:35

data ['response'] работал хорошо, и теперь я могу видеть свои уровни. Спасибо :)

vtomic85 04.04.2018 22:07

Я получил это исключение недавно. Все сводилось к тому, что я пытался ngFor над чем-то, что я считал массивом объектов, но на самом деле это не так. Это был единичный объект или примитив.

Я бы порекомендовал отладить это в браузере и убедиться, что levels на самом деле является массивом.

Привет, да, в моем случае это был единственный объект, так как же его разобрать и назначить массиву модели? например массив сотрудников!

Chakri 16.09.2020 20:02

Вам нужно добавить в свой сервис метод карты и преобразовать ответ в JSON. измените свой Angular Service на следующее:

@Injectable()
export class LevelService {

  constructor(private http: HttpClient) {}

  public getAll() {
    return this.http.get('http://localhost:8000/api/levels/')
    .map(res=>res.json());
  }
  ...
}

Это неверно. HttpClient больше не нуждается в этом дополнительном шаге

Hugo Noro 04.04.2018 19:35

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