简体   繁体   中英

Sort props array on child component Vue.js

I am trying to sort an array of objects that comes from the props on a child component.

However, my sort method Throw s an error. Maybe I am not using the method properly or I can't properly determine the arguments that needs to be passed to it.

What I am trying to do is to sort according to the arguments passed using the click function and calling a method to execute the sort.

The intention here is when I click the arrow on the name, I can then sort it by name, according to the arrow (asc or desc).

This is my component ApplicationsList.vue

<template>
    <div class="modal-backdrop">
    <div class="modal">
      <header class="modal-header">
        <slot name="header">
          <h3>{{job.name}}</h3>

          <button v-if="application.name" type="button" class="btn-close" @click="back">
            <i class="fa fa-arrow-left"></i> Back
          </button>
          <button type="button" class="btn-close" @click="close">
            x
          </button>
        </slot>
      </header>
      <section class="modal-body">
          <div class="row">
              <div v-if="!application.name" class=" col-12 applications-list">
                <table class="table table-bordered">
                    <thead>
                        <tr>
                            <th>Name &nbsp;
                                <i @click="changeSort('name', 'desc')" v-if="this.sortBy === 'name' && this.sortDirection === 'asc' " class="fa fa-sort-up"></i>
                                <i @click="changeSort('name', 'asc')" v-if="this.sortBy === 'name' && this.sortDirection === 'desc' " class="fa fa-sort-down"></i>
                            </th>
                            <th>Email &nbsp;<i class="fa fa-unsorted"></i></th>
                            <th>Date &nbsp;<i class="fa fa-unsorted"></i></th>
                        </tr>
                    </thead>
                    <tbody>
                        <tr class="application-row" v-for="application in job.applications" :key="application.id" :application="application" @click="getApplication(application)">
                            <td>{{application.name}}</td>
                            <td>{{application.email}}</td>
                            <td>Applied {{moment(application.created_at).fromNow()}}</td>
                        </tr>
                    </tbody>
                </table>
            </div>
            <div v-if="application.name" class="col-12 applicant">
                <small>Applied {{moment(application.created_at).fromNow()}}</small>
                <h4 v-if="application.name">Name</h4><p>{{application.name}}</p>
                <h4 v-if="application.email">Email</h4><p>{{application.email}}</p>
                <h4 v-if="application.phone">Phone</h4><p>{{application.phone}}</p>
                <h4 v-if="application.linkedin">Linkedin</h4><p>{{application.linkedin}}</p>
                <h4 v-if="application.cover_letter">Coverletter</h4><p v-html="application.cover_letter"></p>
            </div>
          </div>
      </section>
      <footer class="modal-footer">
    </footer>
  </div>
</div>
</template>


<script>

import moment from 'moment';

export default {

    name: 'ApplicationsList',

    props:['job'],

    data(){
        return{
            application: {name:'', email: '', created_at:'', phone: '', linkedin: '', cover_letter: ''},
            sortBy:'name',
            sortDirection:'asc',
        }
    },

    methods:{

        moment,

        close(){
            this.$emit('closeApplicationsRequest');
        },

        getApplication(application){
            this.application = application;
        },

        back(){
            this.application = '';
        },

        changeSort(sortBy, sortDirection){

            return this.job.application.sort((a, b) => a.sortBy - b.sortBy)

        }

    },


}

</script>

You've got two problems there:

1. Wrong Property accessor

You are using dot notation on your sort function, which means you are trying to access the literal sortBy property of your objects.

What you want, instead, is bracket notation , which allows you to pass a variable to the accessor and, as such, get a dynamically set property. Eg

const obj = {
 prop1: "value"
};

const myProp = "prop1";

obj.myProp; // undefined;
obj[myProp]; // "value"   

2. Wrong comparison function

You are subtracting two strings from one another, which returns NaN . The sorting function cannot work like this. Instead, the comparison function needs to return either 0, lower than 0, or greater than 0.

More information here (MDN)

Working code

function changeSort(sortBy) {
  return this.job.application
    .sort((a, b) => {
      if(a[sortBy] < b[sortBy]) return -1;
      if(a[sortBy] > b[sortBy]) return 1;
      return 0;
    });
}

Extra

I see in your code that you want to add a sorting order, but that wasn't implemented in the function. You could either do:

function changeSort(sortBy, sortDirection) {
  const alphabeticalApplications = this.job.application
    .sort((a, b) => {
      if(a[sortBy] < b[sortBy]) return -1;
      if(a[sortBy] > b[sortBy]) return 1;
      return 0;
    });

  return sortDirection === "asc" ? alphabeticalApplications
   : alphabeticalApplications.reverse();
}

or

function changeSort(sortBy, sortDirection) {
  const sortMultiplier = sortDirection === "asc" ? 1 : -1;
  return this.job.application
    .sort((a, b) => {
      if(a[sortBy] < b[sortBy]) return -1 * sortMultiplier;
      if(a[sortBy] > b[sortBy]) return 1 * sortMultiplier;
      return 0;
    });
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM