I have a component that receive data. In my controller I have:
route::get('/', function() { return inertia('foo', ['data' => Model::all()]) });
On my Vue component:
<template>
<ul>
<li v-for="item in data">{{item.name}}</li>
</ul>
</template>
<script setup>
defineProps({ data: Object })
</script>
My goal is to be able to display the data either by name
or score
depending on the value of a checkbox. I don't think it is a good idea to send the request on the server-side, so I would like to do it on the component.
Unfortunately, props are read only, and it is not possible to do something like this:
<li v-for="Object(data).sort((a, b) => b.score - a.score)">
Any other suggestion?
The type of my props.data
is:
Proxy {0: {…}, 1: {…}, 2: {…}, 3: {…}, 4: {…}, 5: {…}, 6: {…}, 7: {…}, 8: {…}, 9: {…}, 10: {…}, 11: {…}, 12: {…}, 13: {…}, 14: {…}, 15: {…}, 16: {…}}
[[Handler]]: Object
[[Target]]: Object
0: {id: 1, user: null, name: 'foobar', score: 0, …}
1: {id: 2, user: null, name: 'baz', score: 10, …}
And Object(props.data)
doesn't have a sort
method.
CodePudding user response:
<script setup>
import { ref, computed } from "vue";
const props = defineProps({ data: Object });
const sortByScore = ref(true);
const sortBy = computed(() => sortByScore.value ? 'score' : 'name')
const sortedData = computed(() =>
props.data.sort((a, b) => b[sortBy.value] - a[sortBy.value])
);
</script>
And link sortByScore
to the checkbox.
I don't like having to deal with .value
in my controllers, so I'd write it as:
import { reactive, computed, toRefs } from "vue";
const props = defineProps({ data: Object });
const state = reactive({
sortByScore: true,
sortBy: computed(() => state.sortByScore ? 'score': 'name'),
sortedData: computed(() =>
props.data.sort((a, b) => b[state.sortBy] - a[state.sortBy])
)
})
// expose state, so you don't have to use `state.sortedData` in `<template>`
const { sortByScore, sortBy, sortedData } = toRefs(state);
I find reactive()
syntax cleaner, especially in large controllers.
Another advantage of this syntax is you can type the state using only one interface.
Another thing I've seen others do is to name state
as S
and no longer unwrap it for <template>
. Just use it as S.sortByScore
, S.sortedData
, etc.
This way you don't have to re-type all the keys you want exposed. Sometimes I wish there was an equivalent for return {...toRefs(state)}
in <script setup>
.
CodePudding user response:
Give a try to computed property
<script setup>
import { computed } from 'vue'
const props = defineProps({ data: Object })
const sortedData = computed(() => Object(props.data.value).sort((a, b) => b.score - a.score))
</script>
Also, in your v-for
don't forget the :key
with a UUID preferably!