bilcker
bilcker

Reputation: 1120

Vue, Disable all other inputs after radio is clicked

I loop over an array and display a list of radio buttons. I am trying to disable all other radio inputs except for the one selected after one is clicked. All I have been able to manage is to disable all of the radios or the one that is clicked.

I was able to accomplish dynamically adding a class in the v-for loop, so I tried disabling the inputs in the same manner, but everything gets disabled:

:disabled="{'disabled':answer.answerID == isChecked}"

I also tried using a method, but didn't have any luck there either:

/* List data */

"answers":[
      {
        "answerID": "1",
        "answerName": "Blueberries"
      },
      {
        "answerID": "2",
        "answerName": "Apples"
      },
      {
        "answerID": "3",
        "answerName": "Bananas"
      },
      {
        "answerID": "4",
        "answerName": "Pineapple"
      },
      {
        "answerID": "5",
        "answerName": "Strawberries"
      }
  ]

/* Component code */

<template>
    <input
        v-for="(answer, index) in answers"
        :key="index"
        type="radio"
        class="mg-input mg-answer"
        ref="mgAnswer"
        name="mg-answer"
        :value="answer.answerName"
        v-model="answerVal"
        :disabled="disableAnswer(answers, index)"
        :class="{'mg-checked':answer.answerID == isChecked}"
        @click="
          isChecked = answer.answerID
          checkAnswer(answers, index, $event)" />
</template>

<script>
export default {
  data: function () {
    return {
      // Class definer for is checked or not
      isChecked: undefined,
      // Answer Data Properties
      answerVal: '',
      checkedAnswerID: '',
      checkedAnswerElem: '',
    }
  },
  methods: {
    checkAnswer: function (arr, i, event) {
      let mgAnswer = this.$refs.mgAnswer
      this.checkedAnswerID = arr[i].answerID
      this.checkedAnswerElem = mgAnswer[i]

      if (mgAnswer[i].answerName !== this.answerVal) {
        this.answerVal = ''
      }
    },
    disableAnswer: function (arr, i) {
      if (arr[i].answerName !== this.answerVal) {
        return true
      }
    }
  }
}
</script>

Upvotes: 1

Views: 3124

Answers (2)

Helping hand
Helping hand

Reputation: 2920

You can do something like this,

check if input is clicked or if not clicked in that case make disabled set to false.

<input :disabled="disableAnswer(answer)" />

Js

disableAnswer : function(answer){

 if(this.answerVal=="" ||this.answerVal==answer.answerName) {
       return false;
    } else {
       return true;
     }

}

Added Snippet:

function callMe(){
    var vm = new Vue({
        el : '#root',
        data : {
        answerVal:"",
        answers:[
      {
        "answerID": "1",
        "answerName": "Blueberries"
      },
      {
        "answerID": "2",
        "answerName": "Apples"
      },
      {
        "answerID": "3",
        "answerName": "Bananas"
      },
      {
        "answerID": "4",
        "answerName": "Pineapple"
      },
      {
        "answerID": "5",
        "answerName": "Strawberries"
      }
  ]

        
        },
        methods: {
           disableAnswer(item){
            if(this.answerVal=="" ||this.answerVal==item) {
             return false;
           } else {
             return true;
           }

        }
  
        }
        
    })
}
callMe();
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script>
<div id='root'>
<input
        v-for="(answer, index) in answers"
        :key="index"
        type="radio"
        class="mg-input mg-answer"
        ref="mgAnswer"
        name="mg-answer"
        :value="answer.answerName"
        v-model="answerVal"
        :disabled="disableAnswer(answer.answerName)"
       />
 

</div>

Upvotes: 0

tony19
tony19

Reputation: 138226

disableAnswer(answers, index) is evaluated only once upon rendering. Initially, answerVal is null, as no answers have been selected yet, so disableAnswer returns true, causing all radio buttons to be disabled immediately.

A quick fix is to add answerVal as a function argument (i.e., disableAnswer(answers, index, answerVal)), so that the function is re-evaluated when answerVal changes. We have to also modify disableAnswer to ignore null values of answerVal, which would occur at initialization:

disableAnswer(arr, i, answerVal) {
  if (!answerVal) {
    // not yet set
    return;
  }

  if (arr[i].answerName !== answerVal) {
    return true
  }
}

new Vue({
  el: '#app',
  data() {
    return {
      // Class definer for is checked or not
      isChecked: undefined,
      // Answer Data Properties
      answerVal: '',
      checkedAnswerID: '',
      checkedAnswerElem: '',
      "answers":[
        {
          "answerID": "1",
          "answerName": "Blueberries"
        },
        {
          "answerID": "2",
          "answerName": "Apples"
        },
        {
          "answerID": "3",
          "answerName": "Bananas"
        },
        {
          "answerID": "4",
          "answerName": "Pineapple"
        },
        {
          "answerID": "5",
          "answerName": "Strawberries"
        }
      ]
    };
  },
  methods: {
    checkAnswer: function (arr, i, event) {

      let mgAnswer = this.$refs.mgAnswer
      this.checkedAnswerID = arr[i].answerID
      this.checkedAnswerElem = mgAnswer[i]

      if (mgAnswer[i].answerName !== this.answerVal) {
        this.answerVal = ''
      }
    },

    disableAnswer: function (arr, i, answerVal) {
      if (!answerVal) return;
      if (arr[i].answerName !== answerVal) {
        return true
      }
    }
  }
})
input {
  -webkit-appearance: none;
  -moz-appearance: none;
  appearance: none;

  border-radius: 50%;
  width: 16px;
  height: 16px;

  border: 2px solid #999;
  transition: 0.2s all linear;
  outline: none;
  margin-right: 5px;

  position: relative;
  top: 4px;
}

input[disabled] {
  border: 1px solid #ccc;
}

.mg-checked {
  border: 6px solid black;
}
<script src="https://unpkg.com/[email protected]"></script>

<div id="app">
  <input
        v-for="(answer, index) in answers"
        :key="index"
        type="radio"
        class="mg-input mg-answer"
        ref="mgAnswer"
        name="mg-answer"
        :value="answer.answerName"
        v-model="answerVal"
        :disabled="disableAnswer(answers, index, answerVal)"
        :class="{'mg-checked':answer.answerID == isChecked}"
        @click="
          isChecked = answer.answerID
          checkAnswer(answers, index, $event)" />
  
  {{answerVal}}
</div>


You might also find useful a minor refactoring of your code: demo

Upvotes: 3

Related Questions