Чистое решение javascript / jquery для функции Angular 'ng-repeat' с атрибутами данных? - PullRequest
0 голосов
/ 22 июня 2019

Я пытаюсь создать собственную функцию повторителя, аналогичную ng-repeat Angular JS, для перебора данных.Я хочу сделать это исключительно с помощью javascript / jquery и использовать html data-attributes.

Так, например, допустим, у меня есть этот html

    <tr data-repeat="datas">
      <td data-repeat-value="data.name">--</td>
      <td data-repeat-value="data.email">--</td>
    </tr>

, который я хочу создатьфункция, которая достаточно умна, чтобы видеть этот html и отображать сколько угодно <tr> и <td> s, необходимых для правильного вывода данных.

Без атрибутов данных, решение jsвыглядело бы это

    ${datas.map(data => 
        `<tr>
            <td>${data.name}</td>
            <td>${data.email}</td>
        </tr>`).join("")
    }`;

Но как бы я написал js, чтобы использовать data-attributes?

У меня есть codepen , показывающий рабочую версиюбез data-attributes вместе с нерабочей версией с data-attributes.

Любая помощь или руководство будут оценены!

1 Ответ

1 голос
/ 22 июня 2019

Вот решение:

getApiData(url, function(apidata){
    const $template = $('[data-repeat-new]');
    const $container = $template.parent();

    $template.remove();

    $container.append(
        apidata.map(data =>{
            const $snippet = $template.clone(true);
            $snippet.find('[data-repeat-value-new]').each((i, el) => {
                $(el).text(eval($(el).data('repeat-value-new')));
            });
            return $snippet;
        })
    );
});

Полный пример здесь: https://codepen.io/anon/pen/JQWVGG?editors=0010 (единственное изменение в блоке // Not Working).

Что он делает:

  • находит фрагмент DOM, который будет нашим шаблоном (который соответствует селектору [data-repeat-new])
  • хранит ссылку на родительский элемент этого фрагмента - контейнер, в котором мыМы собираемся вставить новое содержимое
  • удаляет этот фрагмент, так как мы не хотим видеть шаблон в конечном выводе
  • для каждого элемента данных, который он делает следующее:
    • шаблон клонов
    • ищет все узлы, которым необходимо вставить значение (т. е. те, которые соответствуют селектору [data-repeat-value-new])
    • и для каждого такого узла он заменяет содержимое узла оцененным выражением (выражение приходитиз значения атрибута data-repeat-value-new, и у нас есть переменная data в контексте eval, так что все просто работает)
  • впоследствии все эти клонированные шаблоны добавляются кконтейнер

, что eval может вызвать вызовk опасно, поэтому:

  • вы можете создать простой синтаксический анализатор выражений, который сократит возможные выражения до некоторого подмножества JS, например, он сможет получать элементы только из фиксированного массива (например, выражения типа data.propertyили data.property[0])
  • или вы можете оставить все как есть, потому что это eval происходит на стороне клиента, а источником кода является узел DOM - если злоумышленник может установить произвольное значение в вашей DOM, он, вероятно, может выполнить любоедругой код тоже

И примечание по значению data-repeat-new: вы получаете данные API в своем коде и никогда не назначаете их, поэтому я не уверен, как можно интерпретировать значениеэтот атрибут.Одним из способов было бы предоставить некоторый репозиторий данных, в котором есть массивы с их именами, например:

const repo = {
    data1: [{id: 'rec1'}, {id: 'rec2'}, {id: 'rec3'}]
};

И тогда в вашем коде вы можете сделать это:

const $template = $('[data-repeat-new]');
const $container = $template.parent();

$template.remove();

const data = repo[$template.data('repeat-new')];

$container.append(
    data.map(data =>{
        const $snippet = $template.clone(true);
        $snippet.find('[data-repeat-value-new]').each((i, el) => {
            $(el).text(eval($(el).data('repeat-value-new')));
        });
        return $snippet;
    })
);
...