Добавление элементов в список из массива json

Я все еще новичок в JavaScript, поэтому извиняюсь, если что-то неясно (или если это действительно просто) - в основном я пытаюсь создать список из массива JSON, который добавляет несколько элементов списка в список (где точный количество добавляемых элементов списка варьируется). Например, ниже - в массиве «роли» три элемента списка, которые необходимо добавить для Джона Смита и четыре для Мэри Тейлор.

rolesData = [
{"name": "John Smith", 
 "title": "project manager", 
 "roles": 
 ["Planning and Defining Scope", "Activity Planning and Sequencing", "Resource Planning"],
}, 
 {"name": "Mary Taylor", 
 "title": "test analyst", 
 "roles": 
 ["design and develop tests for software and systems to detect faults", "analyse the defects and bugs to identify what is causing them", "track the success of the solutions", "keep software and systems documentation up to date"],
}, 

Вот цикл, который я использую для добавления элементов списка. В приведенном выше примере это работает так, как предназначено для второго, поскольку нужно добавить 4 элемента, и он проходит четыре раза, но, очевидно, добавит 4 элемента к тому, для которого также требуется только 3 (последний появляется как undefined) - я немного борюсь с тем, как сделать так, чтобы он проходил через цикл количество раз, которое соответствует количеству элементов в «ролях» - например, если в «ролях» пять элементов, он должен добавить 5 элементов списка. т.е. какое условие должно быть в цикле for: for (i = 0; ???????; i++)?

NB: 'num' - это случайное число, которое генерируется, поэтому, если num равно 0, он получит данные для Джона Смита и т. д.

function createList(num) {

...

var rolesList = document.createElement("ul");

for (i = 0; i < 3; i++){
    var roleItem = document.createElement("li");
    roleItem.innerHTML = rolesData[num].roles[i];
    rolesList.appendChild(roleItem);
}

Обновление: решив вопрос о том, как получить список для заполнения правильными числами при загрузке страницы, я теперь пытаюсь добавить функциональность, при которой, если вы нажмете кнопку, она изменит элементы в списке - это означает что он может измениться с 3 элементов, например, на 4 элемента, и наоборот.

Я попытался адаптировать ответ от @ggorlen (который отлично сработал для создания списка) ниже, но с использованием getElementById, а не элемента create (при создании списка я назначил идентификатор «FeatureList» для ul и «listItem» + счетчик для li , так что для каждого нового созданного listItem идентификатором был listItem1, listItem2 и т. д. - я проверил это в console.log и, похоже, работает правильно). Я считаю, что проблема в том, что если в исходном списке всего 3 элемента, тогда назначено только 3 идентификатора listItem, поэтому, если вы пытаетесь изменить список на один с 4 в нем, нет идентификатора для четвертого, к которому можно перейти - так что Думаю, мой вопрос в том, как мне это сделать, чтобы, если вы меняете элементы, вы могли изменить его на список с большим или меньшим количеством элементов в нем?

const createList = data => {
const list = document.getElementById("featuredList");
count = 1;
   data.forEach(e => {
     const listItem = document.getElementByID("listItem" + count);
     listItem.innerHTML = e;
     list.appendChild(listItem);
     count++;
  });
return list;
};

@RobG Ой, да. Более того, вместо этого полностью избегайте ручных итераций с forEach.

CertainPerformance 10.09.2018 07:49
0
1
126
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

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

Ваш цикл не должен повторяться до фиксированного буквального числа, такого как 3, а должен выполняться до любого свойства массива roles.length. Еще чище, используйте array.forEach, который вызывает функцию для каждого элемента массива и передает текущий элемент в функцию. Я назвал его e для элемента в приведенном ниже примере.

Во-вторых, это плохая практика - обращаться к глобальной переменной из контекста функции. Это ненужная зависимость, нарушающая модульность. Если ваша глобальная область видимости изменится, вы можете непреднамеренно сломать несвязанные функции в другом месте вашего кода, и станет трудно рассуждать о состоянии программы. Передайте все свои данные в функцию как параметры. В этом случае вы можете пропустить параметр num и просто передать сам объект данных.

В-третьих, старайтесь, чтобы функции были как можно более общими. Функция createList должна создать любой список <ul>, который вы хотите, поэтому присвоение универсальным именам переменных и игнорирование свойства .roles на data (вызывающий может об этом беспокоиться) обеспечивает максимальное повторное использование кода.

Наконец, я return отправляю массив узлов обратно вызывающей стороне, чтобы обеспечить гибкость с точки зрения того, что с ним делать (в данном случае, добавляя его в тело документа). Вызывающий принимает случайное десятичное число от 0 до 1 с помощью Math.random() и умножает его на размер массива. Поскольку индексы массива являются целыми числами, поразрядный ~~ (не нет) отрезает десятичную часть числа. Это примерно эквивалентно Math.floor или | 0.

const rolesData = [{
    "name": "John Smith",
    "title": "project manager",
    "roles": ["Planning and Defining Scope", "Activity Planning and Sequencing", "Resource Planning"],
  },
  {
    "name": "Mary Taylor",
    "title": "test analyst",
    "roles": ["design and develop tests for software and systems to detect faults", "analyse the defects and bugs to identify what is causing them", "track the success of the solutions", "keep software and systems documentation up to date"],
  }
];

const createList = data => {
  const list = document.createElement("ul");

  data.forEach(e => {
    const listItem = document.createElement("li");
    listItem.innerHTML = e;
    list.appendChild(listItem);
  });
  
  return list;
};

document.body.appendChild(
  createList(rolesData[~~(Math.random()*rolesData.length)].roles)
);

Если вы предпочитаете лаконичность, reduce (док) - хороший вариант:

const rolesData = [{
    "name": "John Smith",
    "title": "project manager",
    "roles": ["Planning and Defining Scope", "Activity Planning and Sequencing", "Resource Planning"],
  },
  {
    "name": "Mary Taylor",
    "title": "test analyst",
    "roles": ["design and develop tests for software and systems to detect faults", "analyse the defects and bugs to identify what is causing them", "track the success of the solutions", "keep software and systems documentation up to date"],
  }
];

const createList = data =>
  data.reduce((a, e) => {
    const item = document.createElement("li");
    item.innerHTML = e;
    a.appendChild(item);
    return a;
  }, document.createElement("ul")
);

document.body.appendChild(
  createList(rolesData[~~(Math.random()*rolesData.length)].roles)
);

Не могли бы вы описать, для чего нужна подпись тильда (~)?

Manoz 10.09.2018 08:06

Добавил эту информацию. Дайте мне знать, если что-то еще не имеет смысла.

ggorlen 10.09.2018 08:10

@ggorlen Спасибо, это хорошо работает. Я еще не слишком знаком с forEach, но я обязательно рассмотрю его более подробно в ближайшее время. И спасибо за повторное использование кода подсказок и т. д., Это будет действительно полезно

Logan 10.09.2018 08:31

Нет ничего постыдного в использовании традиционного цикла for, если вам это удобно - он быстрее, потому что накладных расходов меньше, чем при создании функций. Если вы это сделаете, важно использовать .length.

ggorlen 10.09.2018 08:45

@ggorlen Будет ли применяться та же основная предпосылка, если я попытаюсь изменить элементы в списке, а не создавать их? Например, если я изначально создал список, в котором было 3 элемента, а затем я хотел изменить его на список, в котором было четыре элемента? Я пробовал немного, но не могу заставить его работать - см. Обновление исходного вопроса, чтобы получить более подробное представление о том, что я пытаюсь сделать.

Logan 10.09.2018 10:45

Я бы разместил новый вопрос, так как похоже, что вы начинаете с нового пути. Вам не нужен count, просто позвоните в forEach с помощью (e, i) =>, чтобы получить доступ к индексу элементов. Во-вторых, поскольку вы используете getElementById, ваш список DOM должен быть создан заранее, и ваш код не показывает никаких признаков того, что это правда. Если вы сделаете это раньше времени, потребуется правильное количество элементов, чтобы работать так, как вы ожидаете. Как написано, ваша новая функция кажется сбитой с толку своей целью (как возвращение списка узлов вызывающей стороне, так и управление DOM). Надеюсь, это поможет.

ggorlen 10.09.2018 16:51

Просто альтернатива использованию уменьшать и использованию appendChild, возвращающего добавленный элемент, так что вы можете создать и добавить за один раз и получить ссылку на добавленный узел.

var rolesData = [
{"name": "John Smith", 
 "title": "project manager", 
 "roles": 
 ["Planning and Defining Scope", "Activity Planning and Sequencing", "Resource Planning"],
}, 
 {"name": "Mary Taylor", 
 "title": "test analyst", 
 "roles": 
 ["design and develop tests for software and systems to detect faults", "analyse the defects and bugs to identify what is causing them", "track the success of the solutions", "keep software and systems documentation up to date"],
}];

function createList(data) {
  var list = document.createElement('ul');
  list.appendChild(data.roles.reduce((frag, role) => {
    var item = frag.appendChild(document.createElement('li'));
    item.innerHTML = role;
    return frag;
  }, document.createDocumentFragment()));
  return list;
}

window.onload = function(){
  document.body.appendChild(createList(rolesData[Math.random()*rolesData.length|0]));
};

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