3

I'm using List.js to display, search, filter, a lot of contents in custom order.

My row is made like this

<div class="content-row">
    <div class="order_id" style="display:none;">{{$item['order']}}</div>
    <div class="order_category" style="display:none;">99999</div>
    <div class="order_source" style="display:none;">99999</div>
    <div class="order_page" style="display:none;">99999</div>
    <div class="content_date" style="display:none;">2016-11-08 11:00:00</div>
    <div class="dd-handle row-container"> I am a row </div>
</div>

I'm trying to order my list of content by multiple order: first order by order_category, then by order_source, then by content_date, and finally by order_page.

In Firefox I tried to order list from less important to more important order and it seems to work, but this didn't work in Chrome:

// Options
var options = {
    valueNames: ['content_id', 'content_date', 'order_id', 'order_category', 'order_source', 'order_page']
};
// Get list Html
var listElement = $("#main_list");
// Init list obj
var listInstance = new List(listElement[0], options);

# ....

// This works in Firefox but not in Chrome!

// Order by page
listInstance.sort('order_page', {
    order: "asc"
});
// then order by date
listInstance.sort('content_date', {
    order: "desc"
});
// then order by list
listInstance.sort('order_source', {
    order: "asc"
});
// finally order by category
listInstance.sort('order_category', {
    order: "asc"
});

# ....

I know that List.js doesn't support multiple sort now but I read that supports custom sort function. Could anyone teach/show me how to build a custom sort function?


Edit:

Thanks to @Dekel I build my own method that use a List.js with custom sort function with 4 level of sort. It works good with a single sort type (ASC or DESC) specified to List.js. I report my code:

/**
 * Sort a List.js list by 4 level of sort
 *
 * @param  {Object} list        [List.js instance]
 * @param  {String} first       [First field to sort]
 * @param  {String} second      [Second field to sort]
 * @param  {String} third       [Third field to sort]
 * @param  {String} fourth      [Fourth field to sort]
 * @param  {String} sort        [sort type: asc || desc]
 * @return {}                   []
 */
var sortList = function(list, first, second, third, fourth, sort) {

    // If list not defined
    if (Utility.empty(list)) {
        console.error("ListManager: can't sort, list is undefined!");
        // Error no list!
        return false;
    }

    // If first order id not defined
    if (Utility.empty(first)) {
        // Set default
        first = "name";
    }

    // If second order id not defined
    if (Utility.empty(second)) {
        // Set default
        second = "born";
    }

    // If third order id not defined
    if (Utility.empty(third)) {
        // Set default
        third = "color";
    }

    // If fourth order id not defined
    if (Utility.empty(fourth)) {
        // Set default
        fourth = "lastName";
    }

    // Check order is not defined
    if (Utility.empty(sort)) {
        // Set default order type to desc 
        sort = "desc";
    }

    // Make list order compatible with list.js fields
    first = "order_" + first;
    second = "order_" + second;
    third = "order_" + third;
    fourth = "order_" + fourth;

    console.log("List Sort: ", first, second, third, fourth);

    // Call sort method of List.js
    list.sort('', {order: sort,
        sortFunction:
            function(a, b) {
                // Compare values with field requested
                return _compareIntegerStringDate(a, b, first)
                    || _compareIntegerStringDate(a, b, second)
                    || _compareIntegerStringDate(a, b, third)
                    || _compareIntegerStringDate(a, b, fourth);
            }
        }
    );
}


/**
 * Compare list.js items value based on filed request.
 * Get correct comparison between integers, strings, or dates.
 *
 * @param  {Object}  a           [List.js item instance]
 * @param  {Object}  b           [List.js item instance]
 * @param  {String}  field       [Field to compare]
 * @return {Integer}             [-X || 0 || +X]
 */
var _compareIntegerStringDate = function(a, b, field) {
    if (Utility.isInt(a.values()[field])) {
        // Compare integer
        return  b.values()[field] - a.values()[field];
    }
    else if(Utility.isDate(a.values()[field], "YYYY-MM-DD HH:mm:ss")){
        // Compare Date
        return Date.parse(b.values()[field]) - Date.parse(a.values()[field]);
    }
    else {
        // Compare strings
        return a.values()[field].localeCompare(b.values()[field]);
    }
}

But if I try to specify the sort type (ASC or DESC) to each value it din't work. I report my code updated with this improvement:

/**
 * Sort a List.js list by 4 level of sort
 *
 * @param  {Object} list        [List.js instance]
 * @param  {String} first       [First field to sort]
 * @param  {String} second      [Second field to sort]
 * @param  {String} third       [Third field to sort]
 * @param  {String} fourth      [Fourth field to sort]
 * @param  {String} firstOrder  [Order type: asc || desc]
 * @param  {String} secondOrder [Order type: asc || desc]
 * @param  {String} thirdOrder  [Order type: asc || desc]
 * @param  {String} fourthOrder [Order type: asc || desc]
 * @return {}              []
 */
var sortList = function(list,
    first, second, third, fourth,
    firstOrder, secondOrder, thirdOrder, fourthOrder,
) {
    console.log("ListManager sort:", list, first, second, third, fourth);
    // If list not defined
    if (Utility.empty(list)) {
        console.error("ListManager: can't sort, list is undefined!");
        // Error no list!
        return false;
    }

    // If first order id not defined
    if (Utility.empty(first)) {
        // Set default
        first = "name";
    }

    // If second order id not defined
    if (Utility.empty(second)) {
        // Set default
        second = "born";
    }

    // If third order id not defined
    if (Utility.empty(third)) {
        // Set default
        third = "color";
    }

    // If fourth order id not defined
    if (Utility.empty(fourth)) {
        // Set default
        fourth = "lastName";
    }

    // Check order if asc or desc
    if (Utility.empty(firstOrder)) {
        // Set order
        firstOrder = "desc";
    }

    // Check order if asc or desc
    if (Utility.empty(secondOrder)) {
        // Set order
        secondOrder = "desc";
    }

    // Check order if asc or desc
    if (Utility.empty(thirdOrder)) {
        // Set order
        thirdOrder = "desc";
    }

    // Check order if asc or desc
    if (Utility.empty(fourthOrder)) {
        // Set order
        fourthOrder = "desc";
    }

    // Make list compatible
    first = "order_" + first;
    second = "order_" + second;
    third = "order_" + third;
    fourth = "order_" + fourth;
    // Make ascending descending compatible
    firstAsc = firstOrder === "asc" ? true : false;
    secondAsc = secondOrder === "asc" ? true : false;
    thirdAsc = thirdOrder === "asc" ? true : false;
    fourthAsc = fourthOrder === "asc" ? true : false;

    console.log("List Sort: ", first, second, third, fourth);
    console.log("List Asc: ", firstAsc, secondAsc, thirdAsc, fourthAsc);

    // Call sort method of List.js
    list.sort('', {order: '',
        sortFunction:
            function(a, b) {
                // Compare values with field requested
                return _compareIntegerStringDate(a, b, first, firstAsc)
                    || _compareIntegerStringDate(a, b, second, secondAsc)
                    || _compareIntegerStringDate(a, b, third, thirdAsc)
                    || _compareIntegerStringDate(a, b, fourth, fourthAsc);
            }
        }
    );
}

/**
 * Compare list.js items value based on filed request.
 * Get correct comparison between integers, strings, or dates.
 *
 * @param  {Object}  a           [List.js item instance]
 * @param  {Object}  b           [List.js item instance]
 * @param  {String}  field       [Field to compare]
 * @param  {Boolean} isAscending [Determinate if is ascending order]
 * @return {Integer}             [-X || 0 || +X]
 */
var _compareIntegerStringDate = function(a, b, field, isAscending) {
    console.log(field + " isAscending " + isAscending);
    if (Utility.isInt(a.values()[field])) {
        // Compare integer
        return isAscending
            ? a.values()[field] - b.values()[field]
            : b.values()[field] - a.values()[field];
    }
    else if(Utility.isDate(a.values()[field], "YYYY-MM-DD HH:mm:ss")){
        // Compare Date
        return isAscending
            ? Date.parse(a.values()[field]) - Date.parse(b.values()[field])
            : Date.parse(b.values()[field]) - Date.parse(a.values()[field]);
    }
    else {
        // Compare strings
        return isAscending
            ? b.values()[field].localeCompare(a.values()[field])
            : a.values()[field].localeCompare(b.values()[field]);
    }
}

Any suggestions to fix that?

Thank you very much!

1 Answer 1

2

List.js support writing your own sort function:

list.sort('name', {sortFunction: function() { ... })

Basically the sort function gets two parameters - two elements from the list, and compare them. If the first element should be first, the function should return -1. If the second item should be first, the function should return 1. If they are equal, the function should return 0.

The List.js library gives you all the value-names inside the a.values(), so you can use them for your comparison.

In the following example I created a list with names and years and the sort function sort the by name (asc) and year (desc).

var options = {
  valueNames: [ 'name', 'born' ]
};

var usersList = new List('users', options);
usersList.sort('', {order: "desc", sortFunction: 
                    function(a, b) {
                      if (Math.abs(b.values().name.localeCompare(a.values().name)) == 1) {
                        return b.values().name.localeCompare(a.values().name)
                      } else {
                        return a.values().born - b.values().born;
                      }
                    }
                   })
<script src="//cdnjs.cloudflare.com/ajax/libs/list.js/1.3.0/list.min.js"></script>

<div id="users">

  <input class="search" placeholder="Search" />
  <button class="sort" data-sort="name">
    Sort
  </button>

  <ul class="list">
    <li>
      <h3 class="name">AAA</h3>
      <p class="born">1986</p>
    </li>
    <li>
      <h3 class="name">AAB</h3>
      <p class="born">1985</p>
    </li>
    <li>
      <h3 class="name">AAC</h3>
      <p class="born">1986</p>
    </li>
    <li>
      <h3 class="name">AAB</h3>
      <p class="born">1983</p>
    </li>
  </ul>

</div>

Sign up to request clarification or add additional context in comments.

1 Comment

Hi @dekel, sorry for the late, thanks for your reply: I build a custom sort function with 4 level of sort comparing integer, strings, and date-strings. It works good with a single sort type asc or desc given to List.js but if I try to select sort type (asc or desc) to each sort level, it doesn't work. I update my question with snippet code. Have you any suggestions?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.