Сложный массив Javascript «редукция элементов» - построение HTML-таблицы на основе элементов массива - PullRequest
0 голосов
/ 14 сентября 2009

У меня есть проект, который требует следующего.

Четыре кода будут объявлены в коде как таковые:

var ROW1 = ['module1'];
var ROW2 = ['module2', 'module3'];
var ROW3 = ['module4', 'module5', 'module6'];
var ROW4 = ['module7', 'module8'];

Каждый элемент этих массивов представляет модуль в настраиваемом HTML-виджете. Исходя из того, какие элементы указаны в каждом массиве, код будет создавать HTML-код, представляющий эти «модули» - каждый массив «ROWx» будет строкой таблицы (), а каждый модуль - ячейкой таблицы () в таблице.

ROW1 может быть пустым (в этом случае он не будет включен в HTML) или иметь один модуль, «module1».

ROW2, ROW3 и ROW4 могут иметь от 0 до 3 модулей (любой из module2 - module8 в любом порядке).

Используя приведенные выше примеры массивов, я программно сгенерировал бы таблицу HTML, подобную этой:

<table>
  <tr id="row1">
    <td colspan="6">[module1]</td>
  </tr>
  <tr id="row2">
    <td colspan="3">[module2]</td>
    <td colspan="3">[module3]</td>
  </tr>
  <tr id="row3">
    <td colspan="2">[module4]</td>
    <td colspan="2">[module5]</td>
    <td colspan="2">[module6]</td>
  </tr>
  <tr id="row4">
    <td colspan="3">[module7]</td>
    <td colspan="3">[module8]</td>
  </tr>
</table>

(Кольспаны просто для того, чтобы сохранить правильную компоновку таблицы; 6 - это наименьшее общее кратное между 1, 2 и 3.)

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

Я уже потратил много времени на создание кода, который абстрагирует создание модуля - он создает макет «оболочки» HTML на основе количества модулей в каждой строке, а затем добавляет содержимое в соответствующую ячейку таблицы, на основе которой модуль должен быть там. Я хотел бы иметь возможность продолжать использовать этот код, поэтому я думаю, что лучший способ сделать это - просмотреть каждый элемент массива перед созданием «оболочки», и, если у меня нет содержимого, удалить этот элемент. из массива. Затем я могу использовать вновь модифицированный массив для создания «оболочки» в обычном режиме - я просто обрабатываю ее заранее, чтобы проверить содержимое в каждом модуле, и, если ни один из них не доступен, действует так, как будто этот модуль никогда не устанавливался в исходном массиве (удалив его в новом массиве, а затем используя его для создания «оболочки»).

Например, допустим, конфигурация настроена так:

var ROW1 = ['module1'];
var ROW2 = ['module4', 'module2'];
var ROW3 = ['module5'];
var ROW4 = ['module7', 'module3', 'module8'];

Я хочу просмотреть каждый элемент в каждом массиве и проверить наличие содержимого в модуле. Допустим, что для «module3» и «module5» нет содержимого. Я хочу затем получить эти массивы:

var ROW1 = ['module1'];
var ROW2 = ['module4', 'module2'];
var ROW3 = ['module7', 'module8'];

Обратите внимание, что произошло со строками - поскольку «module5» был удален, элементы из массива ROW4 были перемещены в ROW3, ​​а затем был удален ROW4. Кроме того, в новом ROW3 (ранее ROW4) «module3» был удален, сдвинув «module8» из положения [2] в положение [1].

Итак:

  • Для всех строк, у которых после удаления модулей остается один или несколько элементов, но у которых нет содержимого, я бы хотел сохранить строку без изменений, даже с одним модулем.
  • Для любых строк, которые заканчиваются без элементов, я бы хотел сместить каждую последующую строку «вверх» в предыдущий массив, в основном вытягивая ряд и сдвигая нижние вверх. HTML-код из этого примера будет выглядеть так:

ДО (в соответствии с запросом конфигурации):

<table>
  <tr id="row1">
    <td colspan="6">[module1]</td>
  </tr>
  <tr id="row2">
    <td colspan="3">[module4]</td>
    <td colspan="3">[module2]</td>
  </tr>
  <tr id="row3">
    <td colspan="6">[module5]</td>
  </tr>
  <tr id="row4">
    <td colspan="2">[module7]</td>
    <td colspan="2">[module3]</td>
    <td colspan="2">[module8]</td>
  </tr>
</table>

ПОСЛЕ (в зависимости от того, какой контент действительно доступен)

<table>
  <tr id="row1">
    <td colspan="6">[module1]</td>
  </tr>
  <tr id="row2">
    <td colspan="3">[module4]</td>
    <td colspan="3">[module2]</td>
  </tr>
  <tr id="row3">
    <td colspan="3">[module7]</td>
    <td colspan="3">[module8]</td>
  </tr>
</table>

Напомним, что ROW1 является особым случаем, поскольку он не влияет на другие строки. Если контент доступен для «module1» (единственный модуль, который может идти в ROW1), тогда ROW1 должен существовать нетронутым. Если контент недоступен, тогда ROW1 может быть удален, но при этом ROW2, ROW3 и ROW4 остаются без изменений (т.е. не сдвигая их каждый вверх по строке). Мне действительно нужно только решение для обработки ROW2, ROW3 и ROW4, поскольку логика для ROW1 довольно проста.

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

Если какой-нибудь гуру JavaScript может поделиться решением для этого, я бы ОЧЕНЬ признателен за это! Спасибо большое.

1 Ответ

4 голосов
/ 14 сентября 2009

Прежде всего, сохраняйте свои строки также в массиве, ваши ROW1 - ROW4 будут вызывать у вас головную боль.

var ROWS = [
 ['module1'],
 ['module4', 'module2'],
 ['module5'],
 ['module7', 'module3', 'module8']
];

Вам также нужен способ удаления элемента. .splice() встроен в массивы и прекрасно работает для удаления элементов.

// lets clear out our disabled modules

var disabledModules = ['module3', 'module5'];

// quick sample function - yours might check for empty content or whatever else...
function isDisabled(module) {  
  for (var i=0, test; test=disabledModules[i]; i++) {
    if (test === module) return true;
  }
  return false;
}

for(var i=0,row; row=ROWS[i]; i++) {
  for (var j=0,module; module=row[j]; j++) {
    // is this module in our disabled modules list?

    if (isDisabled(module)) { // the module is disabled
      row.splice(j,1);
      j--; // so we recheck this point in the array
    }
  }
  if (row.length < 1) {
    // all items were deleted
    ROWS.splice(i,1);
    i--; // so we recheck this point..
  }
}

// ROWS === [["module1"], ["module4", "module2"], ["module7", "module8"]]

Ваш комментарий спросил об используемом синтаксисе цикла for. Это довольно быстрый способ перебрать массивы, которые, как вы знаете, не будут иметь «ложных» значений. Разбивая на части и включая подробное ведение журнала:

 for(
  // Part 1 of for loop: Setup, create two variables, i=0, and row.
  var i=0,row; 
  // Part 2: The test - when false, loop will exit, gets executed pre-loop every time
  // Assignment operator returns the value assigned, so row=ROWS[i] will be undefined
  // (false) when we reach then end of the array.
  row=ROWS[i]; 
  // Part 3: Post loop - increment i
  i++) {

Опасность использования этого метода действительно существует, хотя, если, например, это массив чисел и одно из этих чисел равно 0, цикл завершится рано. Альтернативой было бы написать:

for(var i=0; i<ROWS.length; i++) { 
  var row = ROWS[i];
}
...