Home > Mobile >  How to add a 'Sort By' dropdown to sort a list in Vuejs?
How to add a 'Sort By' dropdown to sort a list in Vuejs?

Time:11-03

I've got a pretty straight forward setup.

Trying to display a list of users with a search box at the top (for actively filtering the search results).

If I use just that the page works and displays fine.

I'm trying to add in an additional dropdown to pick an attribute to sort by (and hopefully add in another dropdown to indicate ascending/descending once I get the first dropdown working).

My current code (with a non-working version of the sort) looks like this:

    <div id="app">
        <section class="mb-3">
            <div class="container">
                <h2>Person Search</h2>
                <h3>
                    <small class="text-muted">Filter people based on the name, location or job</small>
                </h3>
                <h3>
                    <small class="text-muted">
                        Examples: “Jane Doe”, “ABC Building”, or “Math”
                    </small>
                </h3>
                <input type="text" class="form-control" v-model="search_term" placeholder="Begin typing to filter by name, location or job...">
                <!-- THIS WOULD CAUSE THE LIST TO FILTER ALPHABETICALLY BY SELECTED ATTRIBUTE -->
                <select id="sortFilterSelect" name="sort_filter" v-model="sort_filter">
                    <option value="">Sort By...</option>
                    <option value="first_name">First Name</option>
                    <option value="last_name">Last Name</option>
                </select>
            </div>
        </section>
        <section>
            <div class="container">
                <h3>People List : ([[ people_count ]] People)</h3>
                <!-- I ADDED 'sortedPeople' HERE - WHICH BROKE IT -->
                <div v-for="person in filteredPeople | sortedPeople">
                    <div class="card mb-4" :class="person.has_summative_past_due ? 'alert-warning' : ''">
                        <div class="card-body row" >
                            <div class="col">
                                <h4 class="card-title" v-bind:person='person.full_name'><a v-bind:href="'{% url 'commonground:index' %}'   'users/'   person.id">[[ person.full_name ]]</a></h4>
                                <p v-if="person.active_summative" class="card-text">
                                    Active Summative Due Date: [[ person.active_summative.due_date ]]
                                    <span v-show="!person.active_summative.past_due" v-bind:past_due='person.active_summative.past_due' class="badge badge-success">[[ person.active_summative.due_date_status ]]</span>
                                    <span v-show="person.active_summative.past_due" class="badge badge-danger">[[ person.active_summative.due_date_status ]]</span>
                                    <ul class="list-group list-group-flush">
                                        <li class="list-group-item justify-content-between align-items-center" v-for="summary in person.summative_evaluations_summary">
                                            <span class="badge badge-secondary badge-pill">[[summary.evaluation_type__count]]</span> [[ summary.evaluation_type__name ]]
                                        </li>
                                    </ul>
                                </p>
                                <p v-if="!person.active_summative" class="card-text">
                                    No Active Unlocked Summatives
                                </p>
                                <a v-if="person.active_summative" :href="person.active_summative.absolute_url" class="btn btn-primary"><i class="far fa-edit"></i> View / Edit Active Summative</a>
                            </div>
                            <div class="col-auto float-right text-right">
                                <p class="h5">
                                    [[ person.base_location ]]
                                    <div v-if="person.multiple_locations" class="small text-muted"><i class="fal fa-info-circle"></i> User has multiple locations</div>
                                </p>
                                <p class="h5">
                                    [[ person.assignment_job ]]
                                    <div v-if="person.multiple_jobs" class="small text-muted"> <i class="fal fa-info-circle"></i> User has multiple jobs</div>
                                </p>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </section>
    <!-- END OF VUE -->
    </div>

The actual Vue code looks like this:

    <script>
        const app = new Vue({
            delimiters: ['[[', ']]'],
            el: '#app',
            data: {
                people: [],
                people_count: 0,
                search_term: "",
                sort_filter: "",
            },
            computed: {
                filteredPeople:function()
                {
                    var search = this.search_term.toLowerCase();
                    return this.people.filter(function(person){
                        return Object.values(person).some( val => String(val).toLowerCase().includes(search))
                    })
                },
                sortedPeople:function()
                {
                    var sort_filter = this.sort_filter.toLowerCase();
                    console.log('triggered')
                    return this.people.filter(function(person){
                        return Object.values(person).some( val => String(val).toLowerCase().includes(sort_filter))
                    })
                },
            },
            async created () {
                var response = await fetch("{% url 'user-list' %}");
                this.people = await response.json();
                this.people_count = await this.people.length
            }
        })
    </script>

Fairly new to Vue, but I am building this to learn. All help is appreciated!

CodePudding user response:

Check out the simple sample I made: Link

    filteredPeople() {
      return this.people.filter(
        (person) =>
          person.firstname
            .toLowerCase()
            .includes(this.search.toLowerCase().trim()) ||
          person.lastname
            .toLowerCase()
            .includes(this.search.toLowerCase().trim())
      );
    },
    sortedPeople() {
      return this.filteredPeople.sort((a, b) =>
        a[this.sortby].localeCompare(b[this.sortby])
      );
    },

Added asc/dec order: Link

sortedPeople() {
      return this.filteredPeople.sort((a, b) =>
        (this.sort == 'asc') ? a[this.sortby].localeCompare(b[this.sortby]) : b[this.sortby].localeCompare(a[this.sortby])
      );
    },
  • Related