Каков наилучший способ обработки нерегулярных вложенных объектов / массивов с помощью Meteor? - PullRequest
0 голосов
/ 11 января 2019

У меня возникли проблемы с поиском элегантного и эффективного способа обработки нерегулярных вложенных массивов / объектов в nodeJS. Под нерегулярным я подразумеваю массивы / объекты, которые могут иметь 1, 2, 3 или более измерений.

Например, 2 разных случая:

Первый случай:

"head": {
    "firstElement": {
        "Choice1": [
            "Some text",
            "some text"
        ],
        "Choice2": [
            "Some text",
            "Some text"
        ]
    },
    "SecondElement": [
        "Some text",
        "Some text"
    ]
}

Второй случай:

"head": {
    "firstElement": [
        "Some text",
        "Some text"
    ],
    "secondElement": [
        "Some text",
    ]
}

То, что я хочу, - это иметь возможность извлечь все это, сохранить все, кроме «Выборов», которые я не хочу, и, наконец, распечатать это ясно в div.

Ожидаемое:

<div>
   <h1>FirstElement</h1>
       <h2>Choice#</h2>
           <p>Some text</p>
           <p>Some text</p>
   <h1>SecondElement</h1>
      <p>Some text</p>
      <p>Some text</p>
</div>

Вложенный аспект в HTML не проблема, я просто борюсь с алгоритмом.

1 Ответ

0 голосов
/ 14 января 2019

Работа с произвольными уровнями глубины всегда является сложной задачей, особенно когда структура (как в ваших примерах) может дополнительно варьироваться между типами.

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

<template name="recursive">
    {{#with data}}
        {{#if isString this}}
            <!--
            Print string values directly as paragraph.
            No recursion included.
            -->
            <p>{{this}}</p>
        {{else if isArray this}}
            <!--
            If we have an array f values then iterate
            and call a new template instance but don't 
            increase the level, since the values in the 
            array could also be just strings
            -->
            {{#each this}}
                {{> recursive data=this level=level}}
            {{/each}}
        {{else if isObject this}}
            <!--
            Now with an object we need to transform it into
            an iterable version, first (using the mapped helper).
            We also need to increase the level of nesting using incLevel.
            -->
            {{#each map in (mapped this)}}
                <!-- this is to keep the code more tidy and readable -->
                {{> headline level=level title=map.key}}
                {{> recursive data=map.value level=incLevel}}
            {{/each}}
        {{/if}}
    {{/with}}
</template>

Для удобства чтения мы можем извлечь логику, чтобы определить, какой заголовок мы хотим отобразить в собственный шаблон:

<template name="headline">
    {{#if level1 level}}
        <h1>{{title}}</h1>
    {{else if level2 level}}
        <h2>{{title}}</h2>
    {{else}}
        {{level}}
    {{/if}}
</template>

Прочитайте комментарии внутри кода шаблона для объяснения того, что там происходит.

Теперь, из-за сложности предполагаемой логики рендеринга, нам нужны некоторые помощники для

  • обнаружение типов данных
  • определить уровень глубины, увеличить уровень глубины
  • сопоставить объект с повторяемостью
Template.recursive.helpers({
  mapped (obj) {
    return Object.keys(obj).map(key => ({ key, value: obj[ key ] }))
  },
  level() {
    return Template.instance().data.level || 1
  },
  incLevel() {
    const level = Template.instance().data.level
    return level ? level + 1 : 2
  },
  isArray (element) {
    return Array.isArray(element)
  },
  isString (element) {
    return typeof element === 'string'
  },
  isObject (element) {
    return typeof element === 'object'
  }
})

Обратите внимание, что уровни начинаются с одного, потому что ваши заголовки также начинаются с одного. Говоря о заголовках, нам также нужны помощники для заголовка. Шаблон:

Template.headline.helpers({
  level1(lvl) {
    return lvl === 1
  },
  level2(lvl) {
    return lvl === 2
  },
  // ... up to 6
  // then fallback to <strong> if lvl > 6
})

Вы можете назвать шаблон следующим образом (обратите внимание, что я поместил его в качестве примера в <body>):

<body>
{{> recursive data=example1}}
{{> recursive data=example2}}
</body>

Где example1 и example2 являются помощниками, передавая данные в ваш шаблон:

const example1 = {
  'head': {
    'firstElement': {
      'Choice1': [
        'Some text',
        'some text'
      ],
      'Choice2': [
        'Some text',
        'Some text'
      ]
    },
    'SecondElement': [
      'Some text',
      'Some text'
    ]
  }
}

const example2 = {
  'head': {
    'firstElement': [
      'Some text',
      'Some text'
    ],
    'secondElement': [
      'Some text',
    ]
  }
}

Template.body.helpers({
  example1() {
    return Object.values(example1)
  },
  example2() {
    return Object.values(example2)
  }
})

Теперь вы можете удивиться, почему я не включил следующее требование:

оставь все, кроме "Выборов", которые мне не нужны

Это потому, что с таким шаблоном вы уже выполнили сложную задачу:

  • обнаружить структуру
  • решить, как отображать содержимое
  • визуализация контента

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

Так что вы могли бы сделать, чтобы решить эту проблему?

  • Убедитесь, что вы передаете данные только в шаблон, который будет обработан
  • Пусть «родительский» шаблон обрабатывает обработку (удаляя нежелательные варианты выбора), что в основном является задачей, которую можно выполнить без Blaze, поскольку он в основном состоит из поиска и фильтрации.
  • Не допускайте в этот шаблон ничего, что выходит за рамки рендеринга некоторых данных.
  • Если проблемы все еще возникают или возникают проблемы с этим инкапсулированным подходом, пожалуйста, пересмотрите вложенную природу исходных данных. Возможно, вы можете нормализовать вещи, чтобы получить более линейные структурированные данные.
...