1

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!

1 Answer 1

1

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])
      );
    },
Sign up to request clarification or add additional context in comments.

2 Comments

That is a perfect example. Thank you! If I wanted to include a secondary option (for ascending/descending) are there any particular documents you may recommend?
I have added a simple example :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.