TransWikia.com

Почему отсортированная коллекция (Laravel) неверно отображает порядок в компоненте (Vue.js)?

Stack Overflow на русском Asked by Sergii M on February 13, 2021

Господа. Что-то я под вечер нормально так завис. Вообщем суть проблемы.

Имеем коллекцию атрибутов, которая на беке сортируется по полю ‘position’. На беке все отлично, коллекция сортируется правильно, по нужному полю.

Биндю коллекцию в компонент vue, прогоняю перебор, а она выводится в порядке по полю ID. Из компонента прилетает неверно отсортированный объект. В компонент прилетает правильное, на выходе получаем неправильное… Это что за самодеятельность??? И что самое обидное, такую логику с позиционированием использовал нираз, все верно было, а тут дичь прям какая-то.

Код:

public function edit(int $attributeGroupId, AttributeGroupRepository $attributeGroupRepository)
{
    $attributeGroup = $attributeGroupRepository->findAttributeGroupById($attributeGroupId);
    $attributes = $attributeGroup->attributes->sortBy('position');

    return view('admin.pages.attributes.attribute-groups.edit', compact('attributeGroup', 'attributes'));
}

Дебаг:

IlluminateDatabaseEloquentCollection {#1473 ▼
  #items: array:3 [▼
    0 => AppEntityAttributesAttribute {#1527 ▼
      ...
      #attributes: array:7 [▼
        "id" => 1
        "attribute_group_id" => 1
        "name" => "Размер экрана"
        "value_type" => "text"
        "sorting_type" => "alphanumeric"
        "position" => 1
        "display_in_filter" => 1
      ]
      ...
    }
    2 => AppEntityAttributesAttribute {#1525 ▼
      ...
      #attributes: array:7 [▼
        "id" => 4
        "attribute_group_id" => 1
        "name" => "Расширение экрана"
        "value_type" => "text"
        "sorting_type" => "numeric"
        "position" => 2
        "display_in_filter" => 1
      ]
      ...
    }
    1 => AppEntityAttributesAttribute {#1526 ▼
      ...
      #attributes: array:7 [▼
        "id" => 3
        "attribute_group_id" => 1
        "name" => "Цвет корпуса"
        "value_type" => "color"
        "sorting_type" => "position"
        "position" => 3
        "display_in_filter" => 1
      ]
      ...
    }
  ]
}

Бинд:

<attributes-component  v-bind:attributes="{{ json_encode($attributes) }}"/>

И вот что прилетает в компонент:

    attributesData:Object
  0:Object
    attribute_group_id:1
    display_in_filter:1
    id:1
    name:"Размер экрана"
    position:1
    properties:Array[7]
    sorting_type:"alphanumeric"
    value_type:"text"
  1:Object
    attribute_group_id:1
    display_in_filter:1
    id:3
    name:"Цвет корпуса"
    position:3
    properties:Array[0]
    sorting_type:"position"
    value_type:"color"
  2:Object
    attribute_group_id:1
    display_in_filter:1
    id:4
    name:"Расширение экрана"
    position:2
    properties:Array[0]
    sorting_type:"numeric"
    value_type:"text"

Ну и сам перебор, что б не было сомнений, там все банально:

<div v-for="attribute in attributes" :key="attribute.position" class="card">

2 Answers

Проблема до банальности проста. При сортировке коллекции Laravel, сохраняется связь ключ-значение. И вот ключи эти, понятное дело, сортированы не по порядку, что в компоненте доблестная JS и исправляла...

Решение простое, преобразуем коллекцию, и избавляемся от проблемы с ключами:

$attributes = $attributeGroup->attributes->sortBy('position')->values()->all();

и проблемы нет.

Answered by Sergii M on February 13, 2021

С теми данными что дали вы, проблем никаких нет. Я подставил данные и они отобразились в том порядке, в котором задали вы. Вероятнее всего проблема при передаче данных.

Vue.component('attributes-component', {
    props: ['attributes'],
    computed: {
        getAttributes() {
            return JSON.parse(this.attributes);
        },
        getTableHeadKeys() {
            return Object.keys(this.getAttributes[0]);
        }
    },
    template: `
    <div class="attributes-component">
        <table>
            <thead>
                <tr>
                    <th v-for="(key, index) in getTableHeadKeys" :key="index">{{ key }}</th>
                </tr>
            </thead>
            <tbody>
                <tr v-for="attribute in getAttributes" :key="attribute.id">
                    <td v-for="(value, index) in Object.values(attribute)" :key="index">{{ value }}</td>
                </tr>
            </tbody>
        </table>
    </div>
    `
});

Vue.config.devtools = false;
Vue.config.productionTip = false;

new Vue({
    el: "#app",
});
body {
  background: #20262E;
  padding: 20px;
  font-family: Helvetica;
}

#app {
  background: #fff;
  border-radius: 4px;
  padding: 20px;
  transition: all 0.2s;
}

table th, table td {
   border: 1px solid black;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
    <attributes-component attributes='[{"attribute_group_id":1,"display_in_filter":1,"id":1,"name":"Размер экрана","position":1,"sorting_type":"alphanumeric","value_type":"text"},{"attribute_group_id":1,"display_in_filter":1,"id":4,"name":"Расширение экрана","position":2,"sorting_type":"numeric","value_type":"text"},{"attribute_group_id":1,"display_in_filter":1,"id":3,"name":"Цвет корпуса","position":3,"sorting_type":"position","value_type":"color"}]' />
</div>

Answered by MoloF on February 13, 2021

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP