У меня есть запрос ajax, который возвращает json. Если есть одна запись, она возвращает это:
{"key":"My Value 1"}
Если возвращается более одной записи, это массив объектов:
[{"key":"My Value 1"},{"key":"My Value 2"}]
Я хотел бы просто иметь цикл, который обрабатывал бы 1 или несколько возвращаемых объектов, но когда я возвращаю только один объект, response.length не определено:
console.info(typeof response); //Object
console.info(response.length); //undefined
row = '';
Object.values(response).forEach(function(val) {
row += '<tr><td>' + val + '</td></tr>';
});
Проблема в том, что значение response.length не определено, но есть одна возвращенная запись. Я думаю, если бы был возвращен один объект, длина была бы 1? Как проверить один объект, а также обработать несколько? Я думаю, должен быть простой/гибкий способ сделать это?
держите ответ последовательным



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Попробуйте использовать Object.keys(response).length вместо длины.
Лучше исправить на сервере. Если нет возможности сделать
response = response.length?response:[response];
Например
let response = {"key":"My Value 1"}
response = response.length?response:[response]; // force array if no length
tb.innerHTML = response.map((obj) => '<tr><td>' + obj["key"] + '</td></tr>')
.join("")
response = [
{"key":"My Value 2"},
{"key":"My Value 3"}
];
response = response.length?response:[response]; // force array if no length
//console.info(response)
tb.innerHTML += response.map((obj) => '<tr><td>' + obj["key"] + '</td></tr>')
.join("");<table>
<tbody id = "tb"></tbody>
</table>Думаю исправлю на сервере. У меня он динамически возвращал строку или объект, используя активную запись, но я понимаю, что это усложняет ситуацию, и я всегда должен возвращать одно и то же... спасибо!
Вы можете проверить, является ли ответ массивом, используя Array.isArray(response), Если это не массив, создайте массив, используя ответ, и после этого повторите его.
const responseArray = Array.isArray(response) ? response : [response];
responseArray.forEach(element => { // do your thing })
Вы можете проверить тип ответа, если это массив, Array#isArray будет истинным, а с помощью Array#reduce мы можем сократить строку путем конкатенации.
В противном случае, если это один объект, мы можем просто извлечь ключ и сформировать строку.
Но лучше исправить backend API каждый раз возвращать массив. Если это не вариант, используйте решение ниже.
function generateTableRow(response){
let row = '';
if (Array.isArray(response)){
row = response.reduce((acc, {key}) =>{ //using destructuring to get the 'key'
return acc + `<tr><td>${key}</td></tr>`;
}, '');
}else{
row = `<tr><td>${response.key}</td></tr>`;
}
return row;
}
let response = [{"key":"My Value 1"},{"key":"My Value 2"}];
console.info("If array sent");
console.info(generateTableRow(response));
response = {"key":"My Value 1"};
console.info("If object sent");
console.info(generateTableRow(response));Зачем уменьшать? Почему не карту? Я считаю использование сокращения, когда у вас есть результат один к одному, неправильное использование
@mplungjan на самом деле я пытался собрать значения объекта в одну строку, поэтому я подумал об использовании сокращения. Пожалуйста, поправьте меня, если я ошибаюсь, но использование карты приведет к массиву, для которого мне снова нужно использовать соединение (""), чтобы получить результат. Поскольку OP хочет, чтобы конечным результатом была строка :)
Да вы правы. У меня нет проблем с присоединением, как показано в моем обновленном ответе.
Либо измените код на сервере, чтобы он всегда возвращал массив элементов, либо просто оберните ответ в массив на клиенте, если это объект.