Polymer 1.0: Sorting iron-list

泪湿孤枕 提交于 2019-12-12 17:08:42

问题


Google's Polymer creators claim we can manually sort <iron-list> (resolving this issue, perhaps?).

Also see this issue.

Per @emmanuel on the Polymer Slack Site:

You can set list.items = newItems and that will refresh the list.

Here is my code. But it's not working. Please help.

This section of code seems to be the problem.
//this.$.list.items = this.items.sort(this._computeSort(val, ord));
//this.items = this.items.sort(this._computeSort(val, ord));
//this.items.sort(this._computeSort(val, ord));
//this.$.list.items = this.items.sort(this._computeSort(val, ord));

(I commented out everything I tried that failed.)

  • Notice the console logs verify the control values.
  • There is also an inline control value monitor.
  • This proves the sorting logic.

JSBin link

http://jsbin.com/xoqubecado/edit?html,output
<html>

<head>
  <title>My Element</title>
  <script data-require="polymer@*" data-semver="1.0.0" src="http://www.polymer-project.org/1.0/samples/components/webcomponentsjs/webcomponents-lite.js"></script>
  <script data-require="polymer@*" data-semver="1.0.0" src="http://www.polymer-project.org/1.0/samples/components/polymer/polymer.html"></script>
  <base href="http://element-party.xyz/" />
  <link rel="import" href="all-elements.html" />
</head>

<body>
  <dom-module id="my-element">
    <template>
    <style>
      h3 {
        margin-bottom: 0px;
      }
      iron-list {
        padding-bottom: 16px;
      }
      .item {
        @apply(--layout-horizontal);
        margin: 16px 16px 0 16px;
        padding: 20px;
        border-radius: 8px;
        background-color: white;
        border: 1px solid #ddd;
       }
    </style>
    <firebase-collection location="https://dinosaur-facts.firebaseio.com/dinosaurs" data="{{items}}">
    </firebase-collection>
    <h3>Controls</h3>
    <paper-dropdown-menu label="Sort by">
      <paper-menu class="dropdown-content" selected="{{sortVal}}" attr-for-selected="data-sortby">
        <paper-item data-sortby="order">Order</paper-item>
        <paper-item data-sortby="height">Height</paper-item>
      </paper-menu>
    </paper-dropdown-menu>
    <br>
    <paper-toggle-button checked="{{reverse}}">Reverse</paper-toggle-button>
    <br /><br />
    <br><h3>Monitor Control Values</h3>
    <div>Sort by: [[sortVal]]</div>
    <div>Reverse: [[reverse]]</div>
    <br><h3>Iron-List Output</h3>
    <iron-list id="list" items="[[items]]" as="item">
      <template>
        <div class="item">
          Name: [[item.__firebaseKey__]]<br />
          Order: [[item.order]]<br />
          Height: [[item.height]]
        </div>
      </template>
    </iron-list>
    </template>
    <script>
    (function() {
      Polymer({
        is: "my-element",
        properties: {
          items: {
            type: Array,
          },
          sortVal: {
            type: String,
            value: 'order'
          },
          sortOrder: {
            type: Number,
            value: -1, // High to low
            computed: '_computeSortOrder(reverse)'
          }
        },
        observers: [
          'sortChanged(sortVal, sortOrder)'
        ],
        _computeSortOrder: function(bool) {
          return bool ? 1 : -1;
        },
        sortChanged(val, ord) {
          // Also tried what is commented out
          //this.$.list.items = this.items.sort(this._computeSort(val, ord));
          //this.items = this.items.sort(this._computeSort(val, ord));
          //this.items.sort(this._computeSort(val, ord));
          //this.$.list.items = this.items.sort(this._computeSort(val, ord));
          console.log('ord: ' + ord); // All values logged
          console.log('val: ' + val); // Logs are correct
          console.log('items: ' + this.items); // See console log
        },
        _computeSort: function(val, ord) {
          return function(a, b) {
            if (a[val] === b[val]) {
              return 0;
            }
            return (ord * (a[val] > b[val] ? 1 : -1));
          };
        }
      });
    })();
    </script>
  </dom-module>
  <my-element></my-element>
</body>

</html>

This JSBin proves the sorting logic.


回答1:


Per @rob, Polymer Slack Site: (Credit to @arthur for the solution!)

here's a version that sorts: http://jsbin.com/mabadi/2/edit?html,output

the main issue is that if you change the contents of an array, polymer has no idea that you've done that (it can't see inside of an array). So you need to create a copy of your data, sort it, and set that as the new value

it may be helpful to have a separate variable for firebaseItems and sortedItems. That way you don't end up accidentally writing back to firebase

also make sure you give iron-list a height

height: 100% or something like that. And make sure its container has a height as well

http://jsbin.com/vizexodoyi/1/edit?html,output
<html>

<head>
  <title>My Element</title>
  <script data-require="polymer@*" data-semver="1.0.0" src="http://www.polymer-project.org/1.0/samples/components/webcomponentsjs/webcomponents-lite.js"></script>
  <script data-require="polymer@*" data-semver="1.0.0" src="http://www.polymer-project.org/1.0/samples/components/polymer/polymer.html"></script>
  <base href="http://element-party.xyz/" />
  <link rel="import" href="all-elements.html" />
</head>

<body>
  <dom-module id="my-element">
    <template>
    <style>
      h3 {
        margin-bottom: 0px;
      }
      iron-list {
        padding-bottom: 16px;
        height: 100%;
      }
      .item {
        @apply(--layout-horizontal);
        margin: 16px 16px 0 16px;
        padding: 20px;
        border-radius: 8px;
        background-color: white;
        border: 1px solid #ddd;
       }
    </style>
    <firebase-collection location="https://dinosaur-facts.firebaseio.com/dinosaurs" data="{{items}}">
    </firebase-collection>
    <h3>Controls</h3>
    <paper-dropdown-menu label="Sort by">
      <paper-menu class="dropdown-content" selected="{{sortVal}}" attr-for-selected="data-sortby">
        <paper-item data-sortby="order">Order</paper-item>
        <paper-item data-sortby="height">Height</paper-item>
      </paper-menu>
    </paper-dropdown-menu>
    <br>
    <paper-toggle-button checked="{{reverse}}">Reverse</paper-toggle-button>
    <br /><br />
    <br><h3>Monitor Control Values</h3>
    <div>Sort by: [[sortVal]]</div>
    <div>Reverse: [[reverse]]</div>
    <br><h3>Iron-List Output</h3>
    <iron-list id="list" items="[[items]]" as="item">
      <template>
        <div class="item">
          Name: [[item.__firebaseKey__]]<br />
          Order: [[item.order]]<br />
          Height: [[item.height]]
        </div>
      </template>
    </iron-list>
    </template>
    <script>
    (function() {
      Polymer({
      is: "my-element",
      properties: {
        items: {
          type: Array,
        },
        sortVal: {
          type: String,
          value: 'order'
        },
        sortOrder: {
          type: Number,
          value: -1, // High to low
          computed: '_computeSortOrder(reverse)'
        }
      },
      observers: [
        'sortChanged(sortVal, sortOrder)'
      ],
      _computeSortOrder: function(bool) {
        return bool ? 1 : -1;
      },
      sortChanged(val, ord) {
        if (! this.items || this.items.length == 0) {
          return;
        }
        var temp = Array.prototype.slice.call(this.items);
        temp.sort(this._computeSort(val, ord));
        this.items = temp;
        //console.log('ord: ' + ord);
        //console.log('val: ' + val);
        //console.log('items: ' + this.items);
      },
      _computeSort: function(val, ord) {
        return function(a, b) {
          if (a[val] === b[val]) {
            return 0;
          }
          return (ord * (a[val] > b[val] ? 1 : -1));
        };
      }
     });
    })();
    </script>
  </dom-module>
  <my-element></my-element>
</body>

</html>

Optimizing Performance

For those interested in Array.prototype.slice.call(this.items), you might want to study this SO question and the performance comparison of different solutions here.

One apparent performance improvement might be:

// Reference for below: https://stackoverflow.com/questions/3199588/fastest-way-to-convert-javascript-nodelist-to-array
//var temp = Array.prototype.slice.call(this.items);
var temp = [];
var i = this.items.length;
while(i--) {
  //temp.unshift(this.items[i]);
  temp[i] = this.items[i]; 
}


来源:https://stackoverflow.com/questions/34015939/polymer-1-0-sorting-iron-list

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!