聚合物:dom-repeat,如元素的局部变量

时间:2017-03-17 08:35:23

标签: javascript polymer polymer-1.0 web-component dom-repeat

我想创建一个控件,将数据转换为我需要的东西。

目前,我用全局变量解决了这个问题。代码看起来像这样: (小写功能只是为了以简单的方式演示它。通常我想将它用于对象数组。例如,获取某些名称和ID的不同值)

<dom-module id="my-tolower">
  <script>
    "use strict";
    Polymer({
      is: 'my-tolower',
      properties: {
        input: {
          type: String,
          value: "",
        },
        output:{
          type: String,
          value: "",
          notify: true,
        }
      },
      observers:[
        "_inputChanged(input)",
      ],
      _inputChanged: function(newInput, oldInput){
        this.set("output", newInput.toLowerCase());
      }
    });
  </script>
</dom-module>

用法:

<my-tolower input="[[output.name]]" output="{{lower}}">[[lower]]</my-tolower>

如果我仅使用变量lower一次,此解决方案效果很好。在<dom-repeat>内,我遇到了问题。

如何轻松制作仅在my-tolower内可用的自定义变量?与Polymer dom-repeat完全相同的方式是什么?

我看了Polymer's <dom-repeat> sources处的代码,但我不知道它是如何工作的。这在自定义元素中是否可行?我是否需要创建自定义模板?

为了更好地解释我的问题,我添加了一个更详细解释我的问题的示例。

HTMLImports.whenReady(() => {
  Polymer({
    is: 'my-app',
    ready: function(){
      //In my real Problem this value comes from a websocket...
      this.devices = [{
        name: "PC 1",
        components: [
          {
            name: "HDD1",
            processors: [
              {
                type: "Processor1",
                usage: "Dont Know 1"
              },
              { type: "Processor1", usage: "DontKnow2"},
              { type: "Processor2", usage: "DontKnow3"}
            ]
          },
          {
            name: "Another Piece Of Hardware",
            processors: [
              {
                type: "Processor4",
                usage: "Dont Know 1"
              },
              { type: "Processor3", usage: "DontKnow2"},
              { type: "Processor4", usage: "DontKnow3"}
            ]
          }
        ]
      },
      {
        name: "PC 2",
        components: [
          {
            name: "My third piece of hardware",
            processors: [
              {
                type: "Processor1",
                usage: "Dont Know 1"
              },
              { type: "Processor2", usage: "DontKnow2"},
              { type: "Processor3", usage: "DontKnow3"}
            ]
          }
        ]
      }];
      //this.devices must not be changed!
    }
  });
  
  
  Polymer({
    is: 'my-distinct',
    properties: {
      inputs: {
        type: String
      },
      outputs:{
        computed: '_getDistincts(inputs, path)',
        notify: true
      },
      path: {
        type: String,
        value: ""
      }
    },
    _getDistincts(inputs, path){
      let result = [];
      
      for(let key in inputs){
        if(inputs.hasOwnProperty(key)){
          let x = inputs[key];
          if(path && path != ""){
            x = x[path];
          }
          
          if(result.indexOf(x) < 0){
            result.push(x);
          }
          else{
            //Already Exists
          }
        }
      }
      
      return result;
    }
    
  });
  
 
});
<head>
  <base href="https://polygit.org/polymer+1.8.1/components/">
  <script src="webcomponentsjs/webcomponents-lite.js"></script>
  <link rel="import" href="polymer/polymer.html">
</head>
<body>
  <my-app></my-app>
  As you can see, there is always "Processor1", "Processor2" and "Pocessor3" available although this is only the result of the last computers component. You can see the right result (but with duplicates) if you use the comment I made instead.
  
  <dom-module id="my-app">
    <template>
      <ul>
        <template is="dom-repeat" items="[[devices]]" as="device">
          <li>[[device.name]]
          <ul>
            <template is="dom-repeat" items="[[device.components]]" as="component">
              <li>[[component.name]]
                <ul>
                  <!-- This is my code with using distinct -->
                  <my-distinct inputs="[[component.processors]]" 
                      outputs="{{distinctProcessorNames}}" 
                      path="type">
                    <template is="dom-repeat" items="[[distinctProcessorNames]]" as="processorName">
                      <li>[[processorName]]
                        <!-- Here I could iterate over all processors (filtered) and list their usages-->
                      </li>
                    </template>
                  </my-distinct>
                  
                  <!-- This is my code without using distinct. -->
                  <!--template is="dom-repeat" items="[[component.processors]]" as="processor">
                    <li>[[processor.type]]
                      <ul>
                        <li>Used for [[processor.usage]]</li>
                      </ul>
                    </li>
                  </template-->
                </ul>
              </li>
            </template>
          </ul>
          </li>
        </template>
      </ul>
    </template>
  </dom-module>
</body>

Demo

2 个答案:

答案 0 :(得分:1)

正如您所发现的,在<dom-repeat>内声明的属性(在本例中为lower专门用于<dom-repeat>或其迭代。因此,每次迭代都会覆盖之前的lower值,lower之外的<dom-repeat>仍可用。

但是,如果item<dom-repeat>,则可以通过将输出属性附加到item中的每个Object迭代器来实现类似的作用域效果。

例如,考虑一个<x-foo>元素,它接受Object的输入数组,并将每个输入传递给<my-tolower>,这会将新值写入_output(迭代器上的附加属性):

<template is="dom-repeat" items="[[inputs]]" as="x">
  <!-- Attach output to a new property on item (i.e., "_output") -->
  <my-tolower input="[[x.input]]" output="{{x._output}}"></my-tolower>
</template>

&#13;
&#13;
HTMLImports.whenReady(() => {
  Polymer({
    is: 'x-foo',
    properties: {
      inputs: Array
    },

    _toObjArray: function(inputs) {
      // Map inputs into objects so that we can attach properties to each iterator in a dom-repeat
      return inputs.map(input => ({input}));
    }
  });

  Polymer({
    is: 'my-tolower',
    properties: {
      input: {
        type: String,
        value: "",
      },
      output: {
        computed: '_computeOutput(input)',
        notify: true,
      }
    },
    _computeOutput: function(input) {
      return input.toLowerCase();
    }
  });
});
&#13;
<head>
  <base href="https://polygit.org/polymer+1.8.1/components/">
  <script src="webcomponentsjs/webcomponents-lite.js"></script>
  <link rel="import" href="polymer/polymer.html">
</head>
<body>
  <x-foo inputs='["aLPha", "brAVo", "CHarLiE", "DelTA", "epSiLoN"]'></x-foo>

  <dom-module id="x-foo">
    <template>
      <template is="dom-repeat" items="[[_toObjArray(inputs)]]">
        <!-- Attach output to a new property on item (i.e., "_output") -->
        <my-tolower input="[[item.input]]" output="{{item._output}}"></my-tolower>

        <div>
          <span>[[item.input]] -> [[item._output]]</span>
        </div>
      </template>
    </template>
  </dom-module>
</body>
&#13;
&#13;
&#13;

demo

在您的代码中,您有一个嵌套对象,在嵌套dom-repeat中使用。上面的相同技术可以应用于每个嵌套级别,但您的示例仅需要在最内层级别。你可以给<my-distinct>.outputs自己的&#34;本地&#34;通过将输出附加到迭代器(即component)来变量:

<my-distinct outputs="{{component.distinctProcessorNames}}" ...>

然后,您可以在内部dom-repeat中使用它:

<template is="dom-repeat" items="[[component.distinctProcessorNames]]" ...>

&#13;
&#13;
HTMLImports.whenReady(() => {
  Polymer({
    is: 'my-app',
    ready: function(){
      this.devices = [{
        name: "PC 1",
        components: [
          {
            name: "HDD1",
            processors: [
              {
                type: "Processor1",
                usage: "Dont Know 1"
              },
              { type: "Processor1", usage: "DontKnow2"},
              { type: "Processor2", usage: "DontKnow3"}
            ]
          },
          {
            name: "Another Piece Of Hardware",
            processors: [
              {
                type: "Processor4",
                usage: "Dont Know 1"
              },
              { type: "Processor3", usage: "DontKnow2"},
              { type: "Processor4", usage: "DontKnow3"}
            ]
          }
        ]
      },
      {
        name: "PC 2",
        components: [
          {
            name: "My third piece of hardware",
            processors: [
              {
                type: "Processor1",
                usage: "Dont Know 1"
              },
              { type: "Processor2", usage: "DontKnow2"},
              { type: "Processor3", usage: "DontKnow3"}
            ]
          }
        ]
      }];
    }
  });
  
  
  Polymer({
    is: 'my-distinct',
    properties: {
      inputs: {
        type: String
      },
      outputs:{
        computed: '_getDistincts(inputs, path)',
        notify: true
      },
      path: {
        type: String,
        value: ""
      }
    },
    _getDistincts(inputs, path){
      let result = [];
      
      for(let key in inputs){
        if(inputs.hasOwnProperty(key)){
          let x = inputs[key];
          if(path && path != ""){
            x = x[path];
          }
          
          if(result.indexOf(x) < 0){
            result.push(x);
          }
          else {
            //Already Exists
          }
        }
      }
      
      return result;
    }
    
  });
  
 
});
&#13;
<head>
  <base href="https://polygit.org/polymer+1.8.1/components/">
  <script src="webcomponentsjs/webcomponents-lite.js"></script>
  <link rel="import" href="polymer/polymer.html">
</head>
<body>
  <my-app></my-app>
  
  <dom-module id="my-app">
    <template>
      <ul>
        <template is="dom-repeat" items="[[devices]]" as="device">
          <li>[[device.name]]
            <ul>
              <template is="dom-repeat" items="[[device.components]]" as="component">
                <li>[[component.name]]
                  <ul>
                    <my-distinct inputs="[[component.processors]]" outputs="{{component.distinctProcessorNames}}" path="type">
                    </my-distinct>

                    <template is="dom-repeat" items="[[component.distinctProcessorNames]]" as="processorName">
                      <li>[[processorName]]</li>
                    </template>                  
                  </ul>
                </li>
              </template>
            </ul>
          </li>
        </template>
      </ul>
    </template>
  </dom-module>
</body>
&#13;
&#13;
&#13;

your demo with updates

您评论说您不想克隆任何对象或修改输入。遗憾的是,使用上述迭代器属性技术是不可能的。在这种情况下,更好的选择是为<my-distinct>提供一个模板,它将封装任何转换而不会影响输入。

答案 1 :(得分:1)

您正在使用2种不同的Polymer自定义元素<my-app><my-distinct>。 因此,您应该使用正确的<dom-module>语句声明第二个:

<dom-module id="my-distinct">
    <template>
        <template is="dom-repeat" items="[[outputs]]" as="processorName">
            <li>[[processorName]]
        </template>
    </template>
</dom-module>

然后使用您的计算属性(基于属性值)outputs作为items的{​​{1}}值。

演示如下:

&#13;
&#13;
<template is="dom-repeat">
&#13;
HTMLImports.whenReady(() => {
  Polymer({
    is: 'my-app',
    ready: function(){
      //In my real Problem this value comes from a websocket...
      this.devices = [{
        name: "PC 1",
        components: [
          {
            name: "HDD1",
            processors: [
              {
                type: "Processor1",
                usage: "Dont Know 1"
              },
              { type: "Processor1", usage: "DontKnow2"},
              { type: "Processor2", usage: "DontKnow3"}
            ]
          },
          {
            name: "Another Piece Of Hardware",
            processors: [
              {
                type: "Processor4",
                usage: "Dont Know 1"
              },
              { type: "Processor3", usage: "DontKnow2"},
              { type: "Processor4", usage: "DontKnow3"}
            ]
          }
        ]
      },
      {
        name: "PC 2",
        components: [
          {
            name: "My third piece of hardware",
            processors: [
              {
                type: "Processor1",
                usage: "Dont Know 1"
              },
              { type: "Processor2", usage: "DontKnow2"},
              { type: "Processor3", usage: "DontKnow3"}
            ]
          }
        ]
      }];
      //this.devices must not be changed!
    }
  });
  
  Polymer({
    is: 'my-distinct',
    properties: {
      inputs: {
        type: String
      },
      outputs:{
        computed: '_getDistincts(inputs, path)', notify: true
      },
      path: {
        type: String,
        value: ""
      }
    },
    _getDistincts(inputs, path){
      let result = [];
      
      for(let key in inputs){
        if(inputs.hasOwnProperty(key)){
          let x = inputs[key];
          if(path && path != ""){
            x = x[path];
          }
          
          if(result.indexOf(x) < 0){
            result.push(x);
          }
        }
      }
      //console.log( result )
      return result;
    } 
  });  
});
&#13;
&#13;
&#13;