如何在聚合物模板中动态添加元素

时间:2016-01-10 09:08:27

标签: javascript polymer

我有一个dom-repeat模板(Polymer 1.2.3),并希望它根据模型渲染元素。

根据item中的值,模板应呈现按钮或复选框或事先未知的其他内容。这就是我试过的:

<template is="dom-repeat" items=[[myItems]]>
    <div>[[_render(item)]]</div>
</template>

_render函数在这里返回一个DOM元素,但这不起作用(如预期的那样)。

_render: function() {
    return document.createElement('paper-button');
}

如果在_render函数的调用中模板将添加对它将要添加的DOM元素的引用,那么对于这种事情有什么用处。然后我可以用它来按需添加孩子。

2 个答案:

答案 0 :(得分:0)

我也尝试过并且似乎无论如何都不能将元素作为要在dom-repeat中呈现的项目传递。 根据您的问题的复杂性和您想要呈现的内容,我只能想到两个解决方案。

1)这里充斥着dom-if元素,看起来很乱

<script>
Polymer({
  is: 'your-element',
  properties: {
    myItems: {
      type: Array,
      value: [
        { type: 'checkbox', other: 'something', },
        { type: 'button', other: 'something else', },
      ]
    },
  },
  isCheckbox: item => item.type === 'checkbox',
  isButton: item => item.type === 'button',
});
</script>

<template is="dom-repeat" items="[[myItems]]">
  <div>
    <template id="dom-if" if="{{isCheckbox(item)}}">
      <input type="checkbox" other="{{item.other}}" />
    </template>
    <template id="dom-if" if="{{isButton(item)}}"">
      <paper-button other="{{item.other}}" ></paper-button>
    </template>
  </div>
</template>

2)这会在你的外部和内部dom之间留下恼人的自定义重复元素,并且会使访问渲染元素变得更加困难

<dom-module id="custom-repeat">
  <template>
  </template>
</dom-module>

<custom-repeat array="{{anArrayOfElementProperties}}"></custom-repeat>

<script>
HTMLImports.whenReady(function () {
  Polymer({
    is: 'custom-repeat',
    properties: {
      items: {
        type: Array,

        // a default value just for an example
        value: [
          {name: 'paper-fab', icon: 'add' },
          {name: 'iron-icon', icon: 'star' },
          {name: 'paper-fab', icon: 'alarm' },
          {name: 'iron-icon', icon: 'apps' },
        ],
        observer: 'itemsChanged',
      },
    },
    itemsChanged: function(items) {
      // Delete all children
      // Add new children based on items
    },
  });
});
</script>

示例2显示为here

我真的不喜欢任何一个答案,但希望它可以让你度过难关,直到有人找到一种方法来改变dom-repeat元素呈现允许在实际节点中传递的方式,或理解何时传递引用DOM节点。

答案 1 :(得分:0)

我尝试使用记录在案here的Polymer DOM-API挂钩dom-repeat模板的渲染操作。使用这种方法你只需要做这样的事情。

 Polymer.dom(this.$.domrep).observeNodes(function(info) {
     var nList = info.addedNodes.filter(function(node) {
         return (node.nodeType === Node.ELEMENT_NODE && node.tagName === 'DIV')
     });

    this.processNewNodes(nList);
 }) 

processNewNodes函数中,您可以将元素附加到dom-repeat模板呈现的节点。然而,由于不同原因,这不是一个好的解决方案。例如它不能与iron-list中使用的模板一起使用。可能会发生添加节点但节点的模型尚未在模板实例中可用的情况。这意味着您无法根据模型将子节点附加到列表项。

这是我最终使用的解决方案,我很满意:

我为列表项创建了第二个dom-module,我将其用作dom-repeatiron-list元素中的节点。您可以将DOM元素作为属性传递给此list-item元素。

<link rel="import" href="../../bower_components/polymer/polymer.html">

<dom-module id="list-item">
    <template></template>
</dom-module>
<script>
Polymer({
    is: 'list-item',

    properties: {
        renderObject: {
            type: Object,
            observer: '_render'
        }
    },

    _render: function(newV) {
        if (!newV) return true;
        var root = Polymer.dom(this.root);

        // remove previously rendered nodes
        while (root.firstChild) {
            root.removeChild(root.firstChild)
        }

        root.appendChild(newV);

    }
});
</script>

每当您更改模型时,list-item都将丢弃并重新创建渲染节点。如果您不希望删除并重新创建每个模型更改上的项目,那么您应该能够将第二个属性itemValue添加到列表项目中。然后,您可以观察itemValue中的更改,并根据需要调整现有DOM元素。

这种方法将模板化器的动作与模板项的渲染动作分开。因此不会产生任何干扰。