Felix
Felix

Reputation: 174

Vue limit the number of true elements in array

I'm looking for a solution to dynamicly watch the values of an array with objects in vue:

new Vue({
  el: "#app",
  data: {
      options: [
          {"id": 1, "title": "One", "value": false},
          {"id": 2, "title": "Two", "value": false },
          {"id": 3, "title": "Three", "value": false}
      ]
  },

I tried different solutions with watch and methods but none worked properly. How can I watch the objects in "options" for change of "value" and limit the maximum number of true objects to a number in this case 1 for example. If I set 2nd object true the first object need to set to false so that only the last changed object is true?

Upvotes: 0

Views: 621

Answers (2)

muka.gergely
muka.gergely

Reputation: 8329

You just need to update the options, like this (in case of limit: 1):

new Vue({
  el: "#app",
  data: {
    limit: 1, // this is not used in this snippet!
    options: [{
        "id": 1,
        "title": "One",
        "value": false
      },
      {
        "id": 2,
        "title": "Two",
        "value": false
      },
      {
        "id": 3,
        "title": "Three",
        "value": false
      }
    ]
  },
  methods: {
    setToTrue(id) {
      // creating a copy of the options data object
      let options = JSON.parse(JSON.stringify(this.options))
      this.options = options.map(e => {
        const value = e.id === id ? true : false
        return { ...e, value }
      })
    }
  }
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
  <div v-for="option in options" :key="option.id">
    ID: {{ option.id }}<br />
    Title: {{ option.title }}<br />
    Value: <span style="font-weight: 700; cursor: pointer;" @click="setToTrue(option.id)">{{ option.value }}</span><br />
    <hr />
  </div>
</div>

For a higher limit (like you'd allow 2 or more true values), you'd need to come up with the ruleset about which ones to keep (beside the new one) - the strategy (ruleset) could be FIFO, LIFO, etc.

Upvotes: 1

Andres Foronda
Andres Foronda

Reputation: 1409

A computed property does the trick:

...
data: () => ({
  options: [...], // your current options
  trueValuesLimit: 2 // If you want to set the limit as data a property
})
computed: {
  // If limitOn is true, then at least one value property is true
  limitOn() {
    const count = this.options.reduce((acc, option) => {
      // If value is true, then add one to the accumulator
      option.value ? acc++ : null
      return acc
    } , 0)
    // Limit sets to 1, update as required
    return count >= 1

    // You can use a data property to validate the limit
    // return count >= this.trueValuesLimit
  }
}
...

Now you can use limitOn property to enable/disable the input to select/deselect options.

Upvotes: 1

Related Questions