javascriptjqueryjquery-uijquery-ui-draggablelist.js

callback not working in a draggable list with list.js


Im trying to create a draggable list with list.js but when I try to edit, add or delete an item nothing happen, I guess is something with the callbacks but I cant find the solution.

this is my html:

<script src="http://listjs.com/assets/javascripts/list.min.js"></script>
 <div id="contacts">
  <ul id="sortable">
<li class="id">
  <img src="http://lorempixum.com/100/100/nature/1" class="img" >
   <h3>The Grasslands</h3>
    <p class="description">Lorem ipsum dolor sit amet, consectetur adipiscing elit. .</p>
    <td class="edit"><button class="edit-item-btn">Edit</button></td>
     <td class="remove"><button class="remove-item-btn">Remove</button>     </td>
</li>

  <li class="id">
   <img src="http://lorempixum.com/100/100/nature/2" class="img" >
     <h3>Paradise Found</h3>
       <p class="description">Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>
  <td class="edit"><button class="edit-item-btn">Edit</button></td>
    <td class="remove"><button class="remove-item-btn">Remove</button></td>
</li>

 <li class="id">
  <img src="http://lorempixum.com/100/100/nature/3" class="img" >
    <h3 >Smoke On The Water</h3>
     <p class="description">Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>
  <td class="edit"><button class="edit-item-btn">Edit</button></td>
    <td class="remove"><button class="remove-item-btn">Remove</button></td>
</li>

<li class="id">
  <img src="http://lorempixum.com/100/100/nature/4" class="img" >
  <h3>Headline</h3>
  <p class="description">Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>
  <td class="edit"><button class="edit-item-btn">Edit</button></td>
    <td class="remove"><button class="remove-item-btn">Remove</button></td>
</li>
</ul>
<table>
<td class="img">
  <input type="hidden" id="id-field" />
  <input type="text" id="img-field" placeholder="Img" />
</td>
<td class="description">
  <input type="text" id="description-field" placeholder="Description" />
</td>
<td class="add">
  <button id="add-btn">Add</button>
  <button id="edit-btn">Edit</button>
 </td>
 </table>
 </div>

and this is my js code:

/*sortable */
$(function() {
$( "#sortable" ).sortable();
$( "#sortable" ).disableSelection();
});

/* listjs */

var options = {
valueNames: [ 'id', 'description', 'img', ]
};

// Init list
var contactList = new Sortable('contacts', options);

var idField = $('#id-field'),
descriptionField = $('#description-field'),
imgField = $('#img-field'),
addBtn = $('#add-btn'),
editBtn = $('#edit-btn').hide(),
removeBtns = $('.remove-item-btn'),
editBtns = $('.edit-item-btn');

// Sets callbacks to the buttons in the list
refreshCallbacks();

addBtn.click(function() {
contactList.add({
id: Math.floor(Math.random()*110000),
description: descriptionField.val(),
img: imgField.val(),

});
clearFields();
refreshCallbacks();
});

editBtn.click(function() {
var item = contactList.get('id', idField.val())[0];
item.values({
id:idField.val(),
description: descriptionField.val(),
img: imgField.val(),
});
clearFields();
editBtn.hide();
addBtn.show();
});

function refreshCallbacks() {
// Needed to add new buttons to jQuery-extended object
removeBtns = $(removeBtns.selector);
editBtns = $(editBtns.selector);

removeBtns.click(function() {
var itemId = $(this).closest('li').find('.id').text();
contactList.remove('id', itemId);
});

editBtns.click(function() {
var itemId = $(this).closest('li').find('.id').text();
var itemValues = contactList.get('id', itemId)[0].values();
idField.val(itemValues.id);
descriptionField.val(itemValues.description);
imgField.val(itemValues.img);

editBtn.show();
addBtn.hide();
});
}

function clearFields() {
descriptionField.val('');
imgField.val('');

}

Thanks in advance


Solution

  • I have not used listjs, so I do not know if this is what you're trying to do. I did find the following: http://listjs.com/examples/add-get-remove/

    From that and your example, I built this: https://jsfiddle.net/Twisty/q7LhmaLb/6/

    HTML

    <div id="contacts">
      <ul id="sortable" class="list">
        <li class="id">
          <img src="https://lorempixel.com/100/100/nature/1/" class="img">
          <h3 class="title">The Grasslands</h3>
          <p class="description">Lorem ipsum dolor sit amet, consectetur adipiscing elit. .</p>
          <td class="edit">
            <button class="edit-item-btn">Edit</button>
          </td>
          <td class="remove">
            <button class="remove-item-btn">Remove</button>
          </td>
        </li>
    
        <li class="id">
          <img src="https://lorempixel.com/100/100/nature/2/" class="img">
          <h3 class="title">Paradise Found</h3>
          <p class="description">Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>
          <td class="edit">
            <button class="edit-item-btn">Edit</button>
          </td>
          <td class="remove">
            <button class="remove-item-btn">Remove</button>
          </td>
        </li>
    
        <li class="id">
          <img src="https://lorempixel.com/100/100/nature/3/" class="img">
          <h3 class="title">Smoke On The Water</h3>
          <p class="description">Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>
          <td class="edit">
            <button class="edit-item-btn">Edit</button>
          </td>
          <td class="remove">
            <button class="remove-item-btn">Remove</button>
          </td>
        </li>
    
        <li class="id">
          <img src="https://lorempixel.com/100/100/nature/4/" class="img">
          <h3 class="title">Headline</h3>
          <p class="description">Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>
          <td class="edit">
            <button class="edit-item-btn">Edit</button>
          </td>
          <td class="remove">
            <button class="remove-item-btn">Remove</button>
          </td>
        </li>
      </ul>
      <table>
        <td class="img">
          <input type="hidden" id="id-field" />
          <input type="text" id="img-field" placeholder="Img" />
        </td>
        <td class="">
          <input type="text" id="title-field" placeholder="Title" />
        </td>
        <td class="description">
          <input type="text" id="description-field" placeholder="Description" />
        </td>
        <td class="add">
          <button id="add-btn">Add</button>
          <button id="edit-btn">Edit</button>
        </td>
      </table>
    </div>
    

    CSS

    body {
      font-family: sans-serif;
    }
    
    .list {
      list-style: none;
      padding: 0;
      margin: 0;
    }
    
    .list li {
      border: 1px solid #ccc;
      border-radius: 6px;
      padding: 10px;
      margin-bottom: 10px;
    }
    
    .list li:after {
      content: "";
      display: table;
      clear: both;
    }
    
    .list .img {
      display: inline-block;
      float: left;
      margin-right: 5px;
    }
    
    .list .title {
      display: inline-block;
      padding: 0;
      margin: 0;
    }
    
    .list .description {
      font-size: 0.65em;
      padding: 0;
      margin:0;
    }
    

    JavaScript

    /*sortable */
    $(function() {
      $("#sortable").sortable().disableSelection();
    });
    
    /* listjs */
    var options = {
      valueNames: ['id', 'title', 'description', 'img', ]
    };
    
    // Init list
    var contactList = new List('contacts', options);
    
    var idField = $('#id-field'),
      titleField = $("#titleField"),
      descriptionField = $('#description-field'),
      imgField = $('#img-field'),
      addBtn = $('#add-btn'),
      editBtn = $('#edit-btn').hide(),
      removeBtns = $('.remove-item-btn'),
      editBtns = $('.edit-item-btn'),
      sortList = $("#sortable");
    
    // Sets callbacks to the buttons in the list
    refreshCallbacks();
    
    addBtn.click(function() {
      contactList.add({
        id: Math.floor(Math.random() * 110000),
        description: descriptionField.val(),
        img: imgField.val(),
    
      });
      clearFields();
      refreshCallbacks();
      sortList.sortable("refresh");
    });
    
    editBtn.click(function() {
      var item = contactList.get('id', idField.val())[0];
      item.values({
        id: idField.val(),
        description: descriptionField.val(),
        img: imgField.val(),
      });
      clearFields();
      editBtn.hide();
      addBtn.show();
    });
    
    function refreshCallbacks() {
      // Needed to add new buttons to jQuery-extended object
      removeBtns = $(removeBtns.selector);
      editBtns = $(editBtns.selector);
    
      removeBtns.click(function() {
        var itemId = $(this).closest('li').find('.id').text();
        contactList.remove('id', itemId);
      });
    
      editBtns.click(function() {
        var itemId = $(this).closest('li').find('.id').text();
        var itemValues = contactList.get('id', itemId)[0].values();
        idField.val(itemValues.id);
        descriptionField.val(itemValues.description);
        imgField.val(itemValues.img);
    
        editBtn.show();
        addBtn.hide();
      });
    }
    
    function clearFields() {
      descriptionField.val('');
      imgField.val('');
    }
    

    It allows you to sort the list and add items. Since an item is being added dynamically, $("#sortable").sortable("refresh"); should be called when items are added.

    Hope that helps.

    Update 1

    I found a number of little issues and tinkered with the styling more for jQuery UI. Play with it here: https://jsfiddle.net/Twisty/q7LhmaLb/11/

    JavaScript

    /* listjs */
    var options = {
      valueNames: ['id', {
        attr: 'src',
        name: 'img'
      }, 'title', 'description']
    };
    
    // Init list
    var contactList = new List('contacts', options);
    
    var idField = $('#id-field'),
      titleField = $("#title-field"),
      descriptionField = $('#description-field'),
      imgField = $('#img-field'),
      addBtn = $('#add-btn'),
      editBtn = $('#edit-btn').hide(),
      removeBtns = $('.remove-item-btn'),
      editBtns = $('.edit-item-btn'),
      sortList = $("#sortable");
    
    // Sets callbacks to the buttons in the list
    refreshCallbacks();
    
    addBtn.click(function() {
      contactList.add({
        id: Math.floor(Math.random() * 110000),
        title: titleField.val(),
        description: descriptionField.val(),
        img: imgField.val()
      });
      clearFields();
      refreshCallbacks();
      sortList.sortable("refresh");
    });
    
    editBtn.click(function() {
      var item = contactList.get('id', idField.val())[0];
      item.values({
        id: idField.val(),
        title: titleField.val(),
        description: descriptionField.val(),
        img: imgField.val(),
      });
      clearFields();
      editBtn.hide();
      addBtn.show();
    });
    
    function refreshCallbacks() {
      // Needed to add new buttons to jQuery-extended object
      console.log("Callback selectors: ", removeBtns.attr("class"), editBtns.attr("class"));
      removeBtns = $("." + removeBtns.attr("class"));
      editBtns = $("." + editBtns.attr("class"));
    
      removeBtns.click(function(e) {
        console.log(e);
        var itemId = $(this).closest('li').find('.id').text();
        contactList.remove('id', itemId);
      });
    
      editBtns.click(function(e) {
        console.log(e);
        var itemId = $(this).closest('li').find('.id').text();
        var itemValues = contactList.get('id', itemId)[0].values();
        idField.val(itemValues.id);
        titleField.val(itemValues.title);
        descriptionField.val(itemValues.description);
        imgField.val(itemValues.img);
    
        editBtn.show();
        addBtn.hide();
      });
    }
    
    function clearFields() {
      titleField.val("");
      descriptionField.val("");
      imgField.val("");
    }
    
    /*sortable */
    $(function() {
      $("#sortable").sortable().disableSelection();
      $(".edit-item-btn").button({
        icon: "ui-icon-comment",
        showLabel: false
      });
      $(".remove-item-btn").button({
        icon: "ui-icon-close",
        showLabel: false
      });
      $(".buttons").controlgroup();
      $('#search-field').on('keyup', function() {
        var searchString = $(this).val();
        contactList.search(searchString);
      });
    });
    

    I did a lot of little things, as you can see, one is fixing the use of .selector. I switched to .attr("class") to get the class name and used it as a class selector. This works since the element only has 1 class defined. Might hunt around to see if there is better solution.

    This is used in refreshCallbacks() like so:

    // Needed to add new buttons to jQuery-extended object
    removeBtns = $("." + removeBtns.attr("class"));
    editBtns = $("." + editBtns.attr("class"));
    

    This function just re-assigns all the elements (in case any new ones were created) back to the variable. This fixed the issue with "Edit" and "Remove" buttons. I noticed edits were not capturing the Image Source url. I found that here: http://listjs.com/examples/data-attributes-custom-attributes/ So to fix it in your project, we do:

    var options = {
      valueNames: ['id', {
        attr: 'src',
        name: 'img'
      }, 'title', 'description']
    };
    

    That I think will do you well.

    Update 2

    I spoke too soon.

    https://jsfiddle.net/Twisty/q7LhmaLb/12/

    The id was not being read, so edits would always pull up the first item. Fixed by updating the li with a data-id attribute. I had to go in and repair some of the jQuery to line up with this.

    Update 3

    Found another add, when sorting, the order is changed. When this happens, the List Index needs to be updated. Simple fix:

    $("#sortable").sortable({
      update: function(e, ui) {
        contactList.reIndex();
      }
    }).disableSelection();
    

    Example: https://jsfiddle.net/Twisty/q7LhmaLb/18/