Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
194 views
in Technique[技术] by (71.8m points)

What is the proper way of sorting an array of objects in Nativescript Vue?

I'm currently trying to do a very simple sort on an array of items within a Nativescript Vue app, however it is pulling back some very weird results. I have a playground link that recreates the issue.

Basically, when my page loads, the items are ordered based on a data property for sort direction. This is ordered correctly. However, if I then try to change this direction (ascending or descending) then it just orders really strange.

On load, my items are ordered ascending like this: Screenshot of ordered items on load

When I then try to sort them descending, the order changes to this: Screenshot of items incorrectly ordered

When I then try to sort ascending again, the order changes to this: Screenshot of items incorrectly ordered

Here is basically the code from my playground entry - I know some of it is over-engineered but this is just a result of me testing numerous things:

<template>
    <Page>
        <ActionBar title="Sort Test" icon="">
        </ActionBar>
        <StackLayout>
            <StackLayout>
                <Label :text="item.title" textWrap="true"
                    v-for="item in orderedItems" :key="item.id" />
            </StackLayout>
            <Label :text="`Sort Ascending: ${sortAscending}`"
                textWrap="true" />
            <Label :text="`Sort Descending: ${sortDescending}`"
                textWrap="true" />

            <Button text="Sort Ascending" @tap="sortAsc" />
            <Button text="Sort Descending" @tap="sortDesc" />
        </StackLayout>
    </Page>
</template>

<script>
    export default {
        methods: {
            sortAsc() {
                this.sortAscending = true;
                this.sortDescending = false;
            },
            sortDesc() {
                this.sortAscending = false;
                this.sortDescending = true;
            }
        },
        computed: {
            orderedItems() {
                //return (b.date > a.date) ? 1 : (b.date < a.date) ? -1 : 0;
                return this.items.sort((a, b) => {
                    if (this.sortAscending) {
                        // return (a.id > b.id) ? 1 : (a.id < b.id) ? -1 : 0;
                        return a.id - b.id;
                    } else {
                        // return (b.id > a.id) ? 1 : (b.id < a.id) ? -1 : 0;
                        return b.id - a.id;
                    }
                });
            }
        },
        data() {
            return {
                sortAscending: true,
                sortDescending: false,
                items: [{
                        id: 1,
                        title: "Label 1"
                    },
                    {
                        id: 2,
                        title: "Label 2"
                    },
                    {
                        id: 4,
                        title: "Label 4"
                    },
                    {
                        id: 5,
                        title: "Label 5"
                    },
                    {
                        id: 3,
                        title: "Label 3"
                    }
                ]
            };
        }
    };
</script>

<style lang="postcss" scoped></style>

Now, I've found a similar issue that seems to match my exact use case, however changing the behaviour of my orderedItems property doesn't seem to make a difference.

Is there something I'm doing wrong? Is my v-for in the wrong place, or is it a side-effect of using a computed property to display it - should I be using a watch on the sort directions instead to re-order the items data property?

Any help would be appreciated - I haven't tried this on iOS yet but this behaviour is happening in Android.

question from:https://stackoverflow.com/questions/65626790/what-is-the-proper-way-of-sorting-an-array-of-objects-in-nativescript-vue

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

OK, for anyone interested, the above sort solution works fine - I don't know enough to be sure but the problem seems to be when Nativescript is rendering out the items.

The solution I have in place is to add a loading state in between the sorts. So, when someone clicks the sort ascending / descending button, a loading message appears, the sort happens, then the loading state disappears. Below is a pretty rudimentary version:

<template>
    <Page>
       <Label v-if="loadingItems">Loading Items</Label>
       <StackLayout v-else>
          <Label v-for="item in items" :key="item.id" :text="item.title" />
          <Button @tap="sort('asc')" text="Sort Ascending" />
          <Button @tap="sort('desc')" text="Sort Descending" />
       </StackLayout>
</template>

<script>
export default {
    data() {
        return {
            loadingItems: false,
            items: [
                {
                  id: 1,
                  title: "Item 1"
                },
                {
                  id: 3,
                  title: "Item 3"
                },
                {
                  id: 3,
                  title: "Item 3"
                },
                {
                  id: 4,
                  title: "Item 4"
                },
                {
                  id: 5,
                  title: "Item 5"
                }
            ]
        },
        methods: {
            sort(dir) {
                this.items = this.items.sort((a,b) => {
                    return dir == 'asc' ? a.id - b.id : b.id - a.id
                });
            }
        }
    }
</script>

Hope this helps anyone with the same issue


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...