Home > Mobile >  Sorting a vue 3 v-for table composition api
Sorting a vue 3 v-for table composition api

Time:03-09

I have successfully created a table of my array of objects using the code below:

      <div >
    
                <table  ref="tbl" border="1" > 
                    <thead>
             <tr>
               
                <th  scope="col" @click="orderby('b.property')">Property</th>
                 <th  scope="col"> Price </th>
                 <th  scope="col"> Checkin Date </th>
                 <th  scope="col"> Checkout Date </th>
                 <th scope="col" > Beds </th>
             </tr>
         </thead>
         <tbody>
            <tr scope="row"  v-for="(b, index) in properties" :key="index">
                
                <td> {{b.property}} </td>
                <td> {{b.pricePerNight}}</td>
                <td> {{b.bookingStartDate}} </td> 
                <td> {{b.bookingEndDate}} <br> {{b.differenceInDays}} night(s)  </td> 
                <td> {{b.beds}} </td> 
    
            </tr>
         </tbody>
     </table>
      </div>


    <script>

    import {ref} from "vue";
    import { projectDatabase, projectAuth, projectFunctions} from '../../firebase/config'
    import ImagePreview from "../../components/ImagePreview.vue"
    
    export default {
      components: {
        ImagePreview
      },
      setup() {
    
    const properties = ref([]);
    
    //reference from firebase for confirmed bookings
           const Ref = projectDatabase .ref("aref").child("Accepted Bookings");
                Ref.on("value", (snapshot) => {
          properties.value = snapshot.val();
        
        });

        //sort table columns
       const orderby = (so) =>{
        desc.value = (sortKey.value == so)
        sortKey.value = so
        }
      
         return {
          properties,
orderby
        };
      },
    };
    </script>

Is there a way to have each column sortable alphabetically (or numerically for the numbers or dates)? I tried a simple @click function that would sort by property but that didn't work

CodePudding user response:

you can create a computed property and return the sorted array.

It's just a quick demo, to give you an example.

Vue.createApp({
  data() {
    return {
      headers: ['name', 'price'],
      properties: [
        {
          name: 'one',
          price: 21
        },
         {
          name: 'two',
          price: 3
        },
         {
          name: 'three',
          price: 5
        },
         {
          name: 'four',
          price: 120
        }
      ],
      sortDirection: 1,
      sortBy: 'name'
    }
  },
  computed: {
    sortedProperties() {
      const type = this.sortBy === 'name' ? 'String' : 'Number'
      const direction = this.sortDirection
      const head = this.sortBy
      // here is the magic
      return this.properties.sort(this.sortMethods(type, head, direction))
    }
  },
  methods: {
    sort(head) {
      this.sortBy = head
      this.sortDirection *= -1
    },
    sortMethods(type, head, direction) {
       switch (type) {
          case 'String': {
            return direction === 1 ?
              (a, b) => b[head] > a[head] ? -1 : a[head] > b[head] ? 1 : 0 :
              (a, b) => a[head] > b[head] ? -1 : b[head] > a[head] ? 1 : 0 
          }
          case 'Number': {
            return direction === 1 ?
              (a, b) => Number(b[head]) - Number(a[head]) :
              (a, b) => Number(a[head]) - Number(b[head])
          } 
       }
    }
  }
}).mount('#app')
th {
  cursor: pointer;
}
<script src="https://unpkg.com/vue@next"></script>

<div id="app">
  <table>
    <thead>
      <tr>
        <th v-for="head in headers" @click="sort(head)">
        {{ head }}
        </th>
      </tr>
    </thead>
    
    <tbody>
      <tr v-for="(data, i) in sortedProperties" :key="data.id">
          <td v-for="(head, idx) in headers" :key="head.id">
              {{ data[head] }}
          </td>
        </tr>
    </tbody>
  </table>
</div>

CodePudding user response:

For any one else who is stuck this is how i solved the problem from https://www.w3schools.com/howto/tryit.asp?filename=tryhow_js_sort_table_desc:

       //sort table columns
       const sortTable = (n) =>{
var table, rows, switching, i, x, y, shouldSwitch, dir, switchcount = 0;
  table = document.getElementById("myTable");
  switching = true;
  //Set the sorting direction to ascending:
  dir = "asc"; 
  /*Make a loop that will continue until
  no switching has been done:*/
  while (switching) {
    //start by saying: no switching is done:
    switching = false;
    rows = table.rows;
    /*Loop through all table rows (except the
    first, which contains table headers):*/
    for (i = 1; i < (rows.length - 1); i  ) {
      //start by saying there should be no switching:
      shouldSwitch = false;
      /*Get the two elements you want to compare,
      one from current row and one from the next:*/
      x = rows[i].getElementsByTagName("TD")[n];
      y = rows[i   1].getElementsByTagName("TD")[n];
      /*check if the two rows should switch place,
      based on the direction, asc or desc:*/
      if (dir == "asc") {
        if (x.innerHTML.toLowerCase() > y.innerHTML.toLowerCase()) {
          //if so, mark as a switch and break the loop:
          shouldSwitch= true;
          break;
        }
      } else if (dir == "desc") {
        if (x.innerHTML.toLowerCase() < y.innerHTML.toLowerCase()) {
          //if so, mark as a switch and break the loop:
          shouldSwitch = true;
          break;
        }
      }
    }
    if (shouldSwitch) {
      /*If a switch has been marked, make the switch
      and mark that a switch has been done:*/
      rows[i].parentNode.insertBefore(rows[i   1], rows[i]);
      switching = true;
      //Each time a switch is done, increase this count by 1:
      switchcount   ;      
    } else {
      /*If no switching has been done AND the direction is "asc",
      set the direction to "desc" and run the while loop again.*/
      if (switchcount == 0 && dir == "asc") {
        dir = "desc";
        switching = true;
      }
    }
  }
        }
  • Related