Search code examples
javascriptvue.jsmethodscomputed-properties

Multiple .includes in Vue.js computed?


I was trying to have multiple .includes and .filters filter in my Vue.js computed but can't succeed.
HTML:

<input class="searchbar" v-model="filterByName" placeholder="Search By Name" oninput="handleInput(event)">
<button type="button" class="btn btn-lg btn-primary">Advanced [BETA]</button>

<div class="padded">
  <p>
    All 9mm & 9×19mm are 9×19mm Parabellum unless otherwise stated. All Rate of Fire are SEMI-AUTOMATIC unless otherwise
    stated.
  </p>
  <p>** - Still in testing phase (test place)</p>
</div>

<table class="ui celled table">
  <thead>
    <tr>

      <th @click="sortBy='name'">Name</th>
      <th @click="sortBy='cal'">Caliber</th>
      <th @click="sortBy='r'">Range (max-min)(studs)</th>
      <th @click="sortBy='dmg'">Damage</th>
      <th @click="sortBy='cap'">Capacity</th>
      <th @click="sortBy='rpm'">Rate of Fire</th>
      <th @click="sortBy='multi'">Damage Multiplier (Head/Torso)</th>
      <th @click="sortBy='desc'">Description</th>
      <th @click="sortBy='rank'">Rank Unlock</th>
    </tr>
  </thead>
  <tbody>
    <tr v-for="(list, index) in sortedlists" :key="index">

      <td>{{list.name}}</td>
      <td>{{list.cal}}</td>
      <td>{{list.r}}</td>
      <td>{{list.dmg}}</td>
      <td>{{list.cap}}</td>
      <td>{{list.rpm}}</td>
      <td>{{list.multi}}</td>
      <td>{{list.desc}}</td>
      <td>{{list.rank}}</td>
    </tr>
  </tbody>
  <tfoot>
    <tr>
      <th colspan="100%">{{sortedlists.length}} guns</th>
    </tr>
  </tfoot>
</table>

JS

function handleInput(e) {
  var ss = e.target.selectionStart
  var se = e.target.selectionEnd
  e.target.value = e.target.value.toUpperCase()
  e.target.selectionStart = ss
  e.target.selectionEnd = se
}

new Vue({
  el: "#main",
  data: {
    heading: "PF Gun List (WIP)",
    lists: [
      {
        name: "M9",
        cal: "9×19mm",
        dmg: "35-10",
        cap: "15+1 / 105",
        rpm: "780",
        multi: "1.50/1.10",
        desc:
          "A 9mm Italian pistol. One of the first 'wonder nines'. High capacity with deep reserves, light recoil, and high velocity. ",
        r: "40-80",
        rank: "0",
      },
      {
        name: "GLOCK 17 (G17)",
        cal: "9×19mm",
        dmg: "34-10",
        cap: "17+1/102",
        rpm: "780",
        r: "40-90",
        multi: "1.50/1.10",
        desc:
          "A 9mm Austrian pistol renowned for its simplicity and ruggedness. Compared to the M9, it has a higher capacity, but less muzzle velocity.",
        rank: "0",
      },
      {
        name: "M1911",
        cal: ".45 ACP",
        dmg: "48-29",
        cap: "8+1/56",
        rpm: "720",
        r: "55-90",
        multi: "1.40/1.15",
        desc:
          "A classic American pistol brought into the modern age. Very high damage up close, with poor velocity and small magazine size.",
        rank: "8",
      },
      {
        name: "DESERT EAGLE (DEAGLE) L5",
        cal: ".44 MAGNUM",
        dmg: "56-32",
        cap: "8+1/40",
        rpm: "400",
        r: "50-80",
        multi: "2.00/  1.30",
        desc:
          "A modern version of the iconic Israeli-American pistol. This specific model has been lightened as well as upgraded with dual Picatinny rails and a much-needed muzzle brake. Very high damage with the capacity to instantly kill to the head up close, with rough recoil.",
        rank: "18",
      },
      {
        name: "M45A1",
        cal: ".45 ACP",
        dmg: "45-28",
        cap: "10+1/60",
        rpm: "670",
        r: "50-95",
        multi: "1.40/1.15",
        desc:
          "A modern American pistol with many custom parts. High damage, medium capacity, strong recoil.",
        rank: "34",
      },

      {
        name: "FIVE SEVEN",
        cal: "5.7×28mm",
        dmg: "29-22",
        cap: "20+1/100",
        rpm: "800",
        r: "80-120",
        multi: "1.40/1.20",
        desc:
          "A modern Belgian pistol firing a unique caliber. Poor close-in performance, with great ranged performance, high velocity, large magazine, wall penetration and deep reserves.",
        rank: "57",
      },
      {
        name: "ZIP 22",
        cal: ".22 LONG RIFLE",
        dmg: "15-12",
        cap: "10+1/180",
        rpm: "1000 SEMI",
        r: "30-60",
        multi: "2.80/1.00",
        desc:
          "A modern American 'pistol' with questionable quality. Abysmal damage, but with deep reserves and a high headshot multiplier. A weapon so bad it killed a million dollar company. 3 shots to the head at all ranges.",
        rank: "61",
      },
      {
        name: "DESERT EAGLE (DEAGLE) XIX",
        cal: ".50 ACTION EXPRESS",
        dmg: "72-37",
        cap: "7+1/21",
        rpm: "400",
        r: "40-82",
        multi: "2.50/1.40",
        desc:
          "Finally, a gun that lets you make a statement. This semi-automatic hand cannon is chambered in .50 Action Express. It'll probably pulverize your wrists with its recoil, but hey, you can't argue with the stopping power. And you've got the king of mayhem...",
        rank: "102",
      },
      {
        name: "GLOCK 18 (G18)",
        cal: "9×19mm",
        dmg: "30-20",
        cap: "19+1/57",
        rpm: "1100 AUTO",
        multi: "1.40/1.00",
        r: "20-60",
        desc:
          "A 9mm Austrian machine pistol. Fast fire rate with relatively stable handling characteristics.",
        rank: "17",
      },
    ],
    sortBy: "rank",
    filterByName: "",
    counter: 0,
  },

  computed: {
    sortedlists() {
      return this.lists
        .filter((list) => list.name.includes(this.filterByName))
        .sort((a, b) => a[this.sortBy] - b[this.sortBy])
    },
  },
})

So I was trying to have multiple .includes and .filter filters (I want another filter like list => list.name.includes(this.filterByCal), and add another input with "v-model='filterByCal'" Sighs So any helpful answers? Please? The last one was helpful in arranging but wasn't what I wanted. So I would really like som help!


Solution

  • The sorting function incorrectly assumes that all values are numeric:

    .sort((a, b) => a[this.sortBy] - b[this.sortBy]) ❌ values are not numbers
    

    The values are actually strings, and subtracting a string results in NaN, so the sorting breaks.

    To resolve this, you could check the strings for a number, and only then use the difference of the numeric values. Otherwise, use String.prototype.localeCompare to perform the comparison:

    .sort((a, b) => {
      const aVal = a[this.sortBy]
      const bVal = b[this.sortBy]
    
      // only check difference when values are numbers
      if (/^\d+$/.test(aVal) && /^\d+$/.test(bVal)) {
        return aVal - bVal
      } else {
        return aVal.localeCompare(bVal)
      }
    })
    

    demo