带有数据属性的Angular'ng-repeat'函数的纯JavaScript / jquery解决方案?

时间:2019-06-22 11:14:23

标签: javascript jquery arrays angularjs-ng-repeat

我正在尝试创建类似于Angular JS的ng-repeat的自定义转发器函数,以对数据进行迭代。我只想使用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>

没有数据属性,js解决方案看起来会这样

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

但是我怎么写js以利用data-attributes

我有一个codepen展示了没有data-attributes的工作版本以及一个带有data-attributes的非工作版本。

任何帮助或指导将不胜感激!

1 个答案:

答案 0 :(得分:1)

这是解决方案:

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调用可能看起来很危险,所以:

  • 您可以制作简单的表达式解析器,以将可能的表达式简化为JS的某些子集,例如它可能只能从固定数组中获取元素(即像data.propertydata.property[0]这样的表达式)
  • 或者您可以保留它,因为此评估发生在客户端,并且代码源是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;
    })
);