title: Litelement - Table sorting renders wrong values
body: <p>I am trying to sort an HTML table based on it's values in my Lit element. However, I'm running into a problem with my component. Here is an overview of my table;
  <a href="https://i.stack.imgur.com/PQHQ1.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/PQHQ1.png" alt="enter image description here" /></a></p>
  <p><strong>The problem</strong></p>
  <p>In this application, you need to be able to sort on every table header. However, items which are considered 'done' need to move to the bottom of the table. My problem arises whenever I mark an item as done. In the following example I will mark the top todo (task: 123) as done. The expected behaviour is that the todo is moved to the bottom of the table with it's checkbox enabled. This is not however what is the outcome at the moment.</p>
  <p><a href="https://i.stack.imgur.com/ArSUM.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/ArSUM.png" alt="enter image description here" /></a></p>
  <p>As you can see, the todo item with task 123 is moved to the bottom. However, the todo with task 456 also gets it's checkbox marked. This is not desired behaviour and I don't know what's causing it. You can also see that the colors are not correct (this is some styling to show you that a changed todo is being saved, yellow = saving, green = saved and red = error).</p>
  <p><strong>Things I have tried</strong></p>
  <p>Since I don't know what is exactly causing this issue I don't know what I should do. I gave all my inputs/rows/td's id's to make sure nothing gets mixed up, but that doesn't seem to work.</p>
  <p><strong>Code</strong></p>
  <pre><code>import { LitElement, html, css } from 'lit-element';
  
  class TableList extends LitElement {
      static get properties() {
          return {
              data: {
                  type: Array
              },
              primaryKey: {
                  type: String
              },
              defaultSortKey: {
                  type: String
              }
          };
      }
  
      set data(value) {
          let oldValue = this._data;
          this._data = [ ... value];
          this.sortByHeader();
          this.requestUpdate('data', oldValue);
      }
  
      get data() {
          return this._data;
      }
      
      async edit(entry, key, event) {
          this.shadowRoot.getElementById('entry' + entry[this.primaryKey].value).classList.remove('saved');
          this.shadowRoot.getElementById('entry' + entry[this.primaryKey].value).classList.remove('error');
          this.shadowRoot.getElementById('entry' + entry[this.primaryKey].value).classList.add('saving');
  
          if (entry[key].type === &quot;checkbox&quot;) {
              entry[key].value = event.target.checked;
          } else {
              entry[key].value = event.target.value;
          }
  
          if (await update(entry)) {
              this.shadowRoot.getElementById('entry' + entry[this.primaryKey].value).classList.remove('saving');
              this.shadowRoot.getElementById('entry' + entry[this.primaryKey].value).classList.add('saved');
  
              setTimeout(() =&gt; {
                  this.shadowRoot.getElementById('entry' + entry[this.primaryKey].value).classList.remove('saved');
              }, 1000);
          } else {
              this.shadowRoot.getElementById('entry' + entry[this.primaryKey].value).classList.remove('saving');
              this.shadowRoot.getElementById('entry' + entry[this.primaryKey].value).classList.add('error');
  
              setTimeout(() =&gt; {
                  this.shadowRoot.getElementById('entry' + entry[this.primaryKey].value).classList.remove('error');
              }, 5000);
          }
      }
  
      sortByHeader(key) {       
          if (key === undefined) {
              key = this.defaultSortKey;
          }
  
          let oldValue = this.data;
          this._data = [ ... this.data.sort((a, b) =&gt; {
              return a[this.defaultSortKey].value - b[this.defaultSortKey].value 
                          || a[key].value - b[key].value;
          })];
  
          this.requestUpdate('data', oldValue);
      }
  
      renderHeaders() {
          let keys = Object.keys(this.data[0]);
  
          return keys.map(key =&gt; html`
              ${this.data[0][key].visible ?
                  html`
                      &lt;th id=&quot;${'header' + key}&quot; @click=&quot;${() =&gt; this.sortByHeader(key)}&quot;&gt;
                          ${key}
                      &lt;/th&gt;
                  `: ''
              }
          `)
      }
  
      renderRows() {
          return this.data.map(entry =&gt; html`
          &lt;tr id=&quot;${'entry' + entry[this.primaryKey].value}&quot;&gt;
              ${Object.keys(entry).map(key =&gt; html`
                  ${entry[key].visible &amp;&amp; !entry[key].editable ?
                      html`&lt;td&gt;${entry[key].value}&lt;/td&gt;`
                      : ``
                  }
                  ${entry[key].visible &amp;&amp; entry[key].editable ?
                      html`&lt;td id=&quot;${'td' + key + entry[this.primaryKey].value}&quot;&gt;
                              &lt;input
                                  id=&quot;${'input' + key + entry[this.primaryKey].value}&quot;
                                  name=&quot;${'input' + key + entry[this.primaryKey].value}&quot;
                                  type=&quot;${entry[key].type}&quot;
                                  ?checked=&quot;${entry[key].value}&quot;
                                  value=&quot;${entry[key].value}&quot;
                                  @change=&quot;${(event) =&gt; {
                                      this.edit(entry, key, event)
                                  }}&quot;
                              /&gt;
                          &lt;/td&gt;`
                      : ``
                  }
              `)}
          &lt;/tr&gt;
          `)
      }
  
      render() {
          return html`
              &lt;table id=&quot;table-list&quot;&gt;
                  &lt;thead&gt;
                      &lt;tr&gt;
                          ${this.renderHeaders()}
                      &lt;/tr&gt;
                  &lt;/thead&gt;
                  &lt;tbody&gt;
                      ${this.renderRows()}
                  &lt;/tbody&gt;
              &lt;/table&gt;
        `;
      }
  
      static get styles() {
          return css`
              table {
                  width: 100%;
                  border-collapse: collapse;
                  font-family: Arial, Helvetica, sans-serif;
              }
  
              th {
                  padding-top: 12px;
                  padding-bottom: 12px;
                  text-align: center;
                  background-color: #4CAF50;
                  color: white;
              }
  
              tr {
                  text-align: right;
                  -moz-transition: all .2s ease-in;
                  -o-transition: all .2s ease-in;
                  -webkit-transition: all .2s ease-in;
                  transition: all .2s ease-in;
                  background: white; 
                  padding: 20px;
              }
  
              .disabled {
                  color: lightgrey;
              }
  
              .saving {
                  background: yellow;
              }
  
              .saved {
                  background: lightgreen;
              }
  
              .error {
                  background: red;
              }
  
              .sort:after {
                  content: ' ↓';
              }
          `;
      }
  }
  
  export default TableList;
  </code></pre>