Сортировка списка с помощью data-attr и отношений родитель-потомок

#javascript #jquery

#javascript #jquery

Вопрос:

У меня есть список, похожий на этот, который я хочу отсортировать. Он должен сортировать по порядку данных, сначала родительский, а дочерние элементы сразу после.

родительский список с данными -порядок 1

дочерний элемент с данными -порядок 1

дочерний элемент с данными -порядок 2

дочерний элемент с данными -порядок 3

родительский список с данными -порядок 2

дочерний элемент с данными -порядок 1

дочерний элемент с данными -порядок 2

Пример:

 <li class='category parent-category' data-order='1' data-categoryId='5' data-parentCategoryId=''>
   <a>Business Basics</a>
</li>

<li class='category parent-category' data-order='2' data-categoryId='2' data-parentCategoryId=''>
    <a>Back Office Basics</a>
</li>

<li class='category child-category' data-order='1' data-categoryId='3' data-parentCategoryId='5'>
    <a>Core Business</a>
</li>

<li class='category child-category' data-order='2' data-categoryId='4' data-parentCategoryId='5'>
    <a>Product</a>
</li>
  

Желаемый результат:

 <li class='category parent-category' data-order='1' data-categoryId='5' data-parentCategoryId=''>
   <a>Business Basics</a>
</li>

<li class='category child-category' data-order='1' data-categoryId='3' data-parentCategoryId='5'>
    <a>Core Business</a>
</li>

<li class='category child-category' data-order='2' data-categoryId='4' data-parentCategoryId='5'>
    <a>Product</a>
</li>

<li class='category parent-category' data-order='2' data-categoryId='2' data-parentCategoryId=''>
    <a>Back Office Basics</a>
</li>
  

Вот что у меня есть на данный момент:

   $(document).ready(function()
        {
            var orderedCats = $(".category").sort((a, b) =>
            {

                if ($(a).hasClass("parent-category")) {
                    var aCategory = $(a).data("categoryid");
                } else {
                    var aCategory = $(a).data("parentcategoryid");
                }

                if ($(a).hasClass("parent-category")) {
                    var aOrder = 0;
                    var order = $(a).data("order");
                } else {
                    var aOrder = $(a).data("order");

                }

                if ($(b).hasClass("parent-category")) {
                    var bCategory = $(b).data("categoryid");
                } else {
                    var bCategory = $(b).data("parentcategoryid");
                }

                if ($(b).hasClass("parent-category")) {
                    var bOrder = 0;
                } else {
                    var bOrder = $(b).data("order");
                }

                return (aCategory * 1000   aOrder) - (bCategory * 1000   bOrder);
            });

            $(".categories").html(orderedCats);
        });
  

Моя мысль заключалась в том, чтобы умножить родительский порядок данных на 1000, и, если это дочерний элемент, добавить его идентификатор заказа к родителям.

родители 1000, 2000, 3000, …

дочерние элементы 1001, 1002, … , 2001, 2002, …

Но я не могу понять, как связать атрибут parentcategoryid дочернего элемента с родительским categoryid.

Ответ №1:

Вам не нужно умножать числа, вам просто нужно сравнить поле order, когда оба узла являются дочерними или родительскими, и category с ParentCategoryID, если они разные.

Проверьте этот пример — вместо использования html я использовал objects (чтобы я мог запускать его без jQuery), но замена аксессуаров свойств на data('field') должна сработать. Это должно дать вам представление

 let array = [
  { parent: true, order: "1", categoryId: '5', text: 'business Basics' },
  { parent: true, order: "2", categoryId: '2', text: 'Back Office Basics' },
  { parent: false, order: "1", categoryId: '3', parentCategoryId: 5, text: 'Core Business' },
  { parent: false, order: "2", categoryId: '4', parentCategoryId: 5, text: 'Product' },
];
array.sort((a, b) => {
    // if both parent or both child, just compare the order.
    // here you would use hasClass('parent-category')
    if(a.parent === b.parent) {
      // compare order, using .data('order')
      let order1 = parseInt(a.order);
      let order2 = parseInt(b.order);
      return order1 - order2;
    }
    // here one of both is a child. Compare the categoryId of parent against parentCategory of child
    return a.parent ? parseInt(a.categoryId) - b.parentCategoryId : parseInt(b.categoryId) - a.parentCategoryId;
     
 });
console.log(array);  

Ответ №2:

В итоге я добавил новый атрибут данных, data-allorder, и установил его перед сортировкой, поэтому мне нужно было отсортировать только один атрибут. Вот как я решил это.

 $('.category').each(function() {
    // if parent, set data-allorder to 1000 x data-order
    if ($(this).hasClass('parent-category')) {
        let parentOrder = parseInt($(this).attr('data-order'));
        $(this).attr('data-allorder', (parentOrder * 1000));
    }

    if ($(this).hasClass('child-category')) {
        // find data-allorder of parent, get child data-order, add, set child data-allorder
        let parentCategoryId = $(this).attr('data-parentcategoryid');
        let findParent = $('.categories').find('[data-categoryid="'   parentCategoryId   '"]');
        let parentAllOrder = parseInt($(findParent).attr('data-allorder'));
        let childOrder = parseInt($(this).attr('data-order'));
        $(this).attr('data-allorder', (parentAllOrder   childOrder));
    }
});

$(".categories li").sort(sort_li)
    .appendTo('.categories');

function sort_li(a, b) {
    return ($(b).data('allorder')) < ($(a).data('allorder')) ? 1 : -1;
}