polymer-2.xsortablejs

Two sortable items dragged if trying to move just one card from the sortable group


I have implemented sortablejs in Polymer2.0 element. I am able to drag and drop the item from group. The issue I am facing now is that randomly, not sure why and how, but 2 cards or items gets moved in a group list. Here's the screenshots.

todos is an object which contains group of lists which have array of items.

List https://www.dropbox.com/s/9wp6vv668p3ckr2/Screenshot%202019-04-30%2007.18.16.png?dl=0

End state when dropped (you see 2 cards moved to the new column which I don't want. I only wanted one card to move) https://www.dropbox.com/s/int4uyyl3945tjv/Screenshot%202019-04-30%2007.18.50.png?dl=0

Code: Polymer element html

 <div class="board­__sprint">
         <template is="dom-repeat" items="{{todos}}" as="row" restamp>
           <div class="list">
             <div class="list­-content">
               <div style="float: left; width: 100%; text-align: center;">
                 <div style="float: left; width: 80%; text-align: left; padding-top: 10px;">
                   <h7 style="color: black; font-size: 20px; font-weight: 800; padding-left: 10px;margin-top: 5px;">
                  [[row.tasks.length]]
                </h7>
                <h7 style="color: black; font-size: 12px; font-weight: 200; padding: 2px; margin-top: 5px;">
                  [[row.title]]
                </h7>
              </div>
              <div style="float: left; width: 20%; text-align: center;">
                <paper-icon-button icon="icons:delete-sweep" style="color: grey;" id="deleteNote" row="[[row]]"
                  on-tap="_removeColumnTriggerDialog"></paper-icon-button>
              </div>
            </div>
            <div style="display: table;">
              <div style="width: 90%; height: 3px; background: #0c66b5;">
                <h7>&nbsp;</h7>
              </div>
              <div id="myid[[row.id]]" class="list-group" style="min-height: 120px;">
                <template is="dom-repeat" items="{{row.tasks}}" as="todo" restamp>
                  <!-- <div class$="{{determineDragable(todo)}}"> -->
                  <div class="item">
                    <div class="ticket" data-index$="{{todo.id}}">
                      <paper-card style="float:center; width: 100%;" class="singleColor" data-index$="{{todo}}"
                        data-index$="{{row}}">
                        <div style="float:left; width: 15%" style$="{{getRandomInt(0, 20)}}">
                          <h7>&nbsp;</h7>
                        </div>
                        <div style="width: 100%">
                          <div style="float: left; width: 15%; vertical-align:center">

                            <px-icon icon="px-vis:pin"></px-icon>
                          </div>
                          <div style="float: left; width: 70%">
                            <h7 class="banksTitle" style="color: black; font-size: 12px; text-align:left;">
                              <b>[{{index}}]</b> &nbsp; &nbsp; [[todo.actTitle]]
                            </h7>
                            <h7 class="banksTitle" style="color: grey; font-size: 12px; text-align:left;">
                              [[todo.actDesc]]
                            </h7>
                          </div>
                          <template is="dom-if" if="{{checkDummy(todo)}}">
                            <div style="float: left; width: 15%;">
                              <paper-icon-button icon="icons:close" style="color: grey;" id$="bt_readmore"
                                todo="[[todo]]" row="[[row]]" on-tap="_moveDel"></paper-icon-button>
                            </div>
                          </template>
                          <template is="dom-if" if="{{checkDummyNot(todo)}}">
                            <div style="float: left; width: 15%;">
                              <paper-icon-button icon="image:crop-square" style="color: grey;" id$="bt_readmore"
                                todo="[[todo]]" row="[[row]]" on-tap=""></paper-icon-button>
                            </div>
                          </template>
                        </div>
                        <div>
                          <h5>&nbsp;</h5>
                        </div>
                        <div style="width: 100%;display: table;">
                          <div style="float: left; width: 15%;">

                            &nbsp;
                          </div>
                          <div style="float: left; width: 70%; text-align: center;">
                            <template is="dom-if" if="{{checkDummy(todo)}}">
                              <paper-icon-button icon="av:playlist-add-check" style="color: green;"
                                id$="bt_readmore" todo="[[todo]]" row="[[row]]" on-tap=""></paper-icon-button>
                            </template>
                            <template is="dom-if" if="{{checkDummy(todo)}}">
                              <paper-icon-button icon="editor:attach-file" style="color: maroon;" id$="bt_readmore"
                                todo="[[todo]]" row="[[row]]" on-tap=""></paper-icon-button>
                            </template>
                            <template is="dom-if" if="{{checkDummy(todo)}}">
                              <paper-icon-button icon="editor:border-color" style="color: grey;" id$="bt_readmore"
                                todo="[[todo]]" row="[[row]]" on-tap=""></paper-icon-button>
                            </template>
                          </div>
                          <div style="float: right; width: 15%;">

                            &nbsp;
                          </div>
                        </div>
                      </paper-card>
                    </div>
                  </div>
                </template>
              </div>
            </div>
            <div>
              <h5>&nbsp;</h5>
            </div>
            <div class="addTicket">
              <paper-button raised class="blue" on-tap="_addTicketDialog" row={{row}}>Add Ticket</paper-button>
            </div>
          </div>
        </div>
      </template>
    </div>

and the JS script specific to onAdd event of sortablejs

_todosChanged() {
      setTimeout(() => {
        console.log('this.todos.length = ' + this.todos.length);
        var self = this;
        if (this.todos !== null || this.todos !== undefined) {
        var lowestOrder = 0;
        var highestOrder = 0;
        var options = {
          group: 'shared',
          animation: 200,
          sort: false,
          draggable: ".item",
          onAdd: function (evt) {
            console.log('---FROM----');
            console.log(evt.from.id);
            console.log('---TO----');
            console.log(evt.to.id);
            console.log('---ITEM----');
            console.log(evt.item.innerText);
            var foundFrom = false;
            var fromId = evt.from.id.substr('myid'.length);
            var fromCol;
            var foundTo = false;
            var toId = evt.to.id.substr('myid'.length);
            var toCol;
            console.log('fromId =' + fromId + '  toId =' + toId);
            self.todos.forEach(child => { //todos = 1, 3, 4 & row = 3
              if (!foundTo) {
                if (child.id === toId) {
                  foundTo = true;
                  toCol = child;
                }
              }
              if (!foundFrom) {
                if (child.id === fromId) {
                  foundFrom = true;
                  fromCol = child;
                }
              }
            });
            console.log('toCol = ' + JSON.stringify(toCol));
            console.log('fromCol = ' + JSON.stringify(fromCol));
            //find item in from col
            var str = evt.item.innerText;
            var itemKey = str.substr(0, str.indexOf(':'));
            itemKey = itemKey.substr(itemKey.indexOf('KEY-')).substr('KEY-'.length);
            console.log('itemKey = ' + itemKey);
            var arrItemToRemove = fromCol.tasks;
            console.log('arrItemToRemove = ' + JSON.stringify(arrItemToRemove));
            var indexItem = -1;
            for (var i = 0; i < arrItemToRemove.length; i++)
              if (arrItemToRemove[i].id === itemKey) indexItem = i;
            console.log('indexItem = ' + indexItem);
            if (indexItem < 0 || indexItem > arrItemToRemove.length) {
              document.getElementById('toastError').show('No item found');
            } else {
              // console.log('indexItem=' + indexItem);
              var newItemToPush = arrItemToRemove[indexItem];
              console.log('newItemToPush=' + JSON.stringify(newItemToPush));
              //now add the item to the right
              var arr = toCol.tasks;
              if (arr === null || arr === undefined) arr = [];
              arr.push({
                'actTitle': newItemToPush.actTitle,
                'actDesc': newItemToPush.actDesc,
                'actDt': newItemToPush.actDt,
                'parent': toCol.order,
                'id': newItemToPush.id
              });
              console.log('arr=' + JSON.stringify(arr));
              self.$.query.ref.child(toCol.$key).child('tasks').set(arr);
              var nwArr = arrItemToRemove.splice(indexItem, 1);
              document.getElementById('toastShort').show('Data moved: ' + newItemToPush.actTitle);
              self.$.query.ref.child(fromCol.$key).child('tasks').set(arrItemToRemove);
            }
          },
        };
        this.todos.forEach(child => {
          if (lowestOrder > child.order) lowestOrder = child.order;
          if (highestOrder < child.order) highestOrder = child.order;
          // console.log(child.id);
          var selector = this.shadowRoot.querySelector('#myid' + child.id);
          Sortable.create(selector, options);
        });
        console.log('lowestOrder=' + lowestOrder + ' highestOrder=' + highestOrder);
        this.set('order', highestOrder);
      }
    });

  }

Solution

  • Ok ... this is what I did to resolve the issue

    1. firebase query is async so I used observer function to update the dummy variable which is used in dom-template. I used async to do that.

    2. The real issue was when you remove element from list that sortablejs has used to render the items. By use of Dummy variable that is copy of firebase object I was able to avoid this issue.

    3. I offline sync the object when user leaves the page. It works fine now.