vue.js/vue.js 기능

[vue.js] radio click시 validation 체크 후 checked 제어 문제 및 해결 방법

반응형

문제

이번 프로젝트에서 radio 버튼 클릭시 validation으로 check를 막는 기능이 필요했다. 보통 vue 개발하면 radio는 v-model로 하니 v-model 데이터만 초기화 하면 되겠지 하는 생각을 하며 개발 진행했는데 되지 않아서 테스트한 내용과 해결 방법을 정리해보려고 한다.

 

기능

radio 버튼이 클릭시 validation 을 체크해서 click을 막는다.

 

1차 테스트

소스

<template>
  <div class="text-center">
    <input type="radio" id="one" name="number" value="One" v-model="picked">
    <label for="one">One</label>
    <br>
    <input type="radio" id="two" name="number" value="Two" v-model="picked">
    <label for="two">Two</label>
    <br>
    <span>선택: {{ picked }}</span>
    <br>
    <button type="button" @click="reset"> radio data 초기화</button>
  </div>
</template>

<script>
  export default {
    watch:{
      picked(){
        console.log('watch : ', this.picked)
      }
    },
    data(){
      return{
        picked: ''
      }
    },
    methods:{
      reset(){
        console.log('button : ', this.picked)
        this.picked= ''
      }
    }
  }
</script>

 

테스트

 

v-model 데이터를 picked으로 선언하고 this.picked = '' 으로 간단하게 처리했다.

button 으로 테스트한것 처럼 간단하게 데이터만 초기화 하면 되겠지 생각했지만..

 

2차 테스트

소스

<template>
  <div class="text-center">
    <input type="radio" id="one" name="number" value="One" v-model="picked" @click="radioClick" @change="radioChange">
    <label for="one">One</label>
    <br>
    <input type="radio" id="two" name="number" value="Two" v-model="picked" @click="radioClick" @change="radioChange">
    <label for="two">Two</label>
    <br>
    <span>선택: {{ picked }}</span>
    <br>
    <button type="button" @click="reset"> radio data 초기화</button>
  </div>
</template>

<script>
  export default {
    watch:{
      picked(){
        console.log('watch : ', this.picked)
      }
    },
    data(){
      return{
        picked: ''
      }
    },
    methods:{
      reset(){
        console.log('button : ', this.picked)
        this.picked= ''
      }
      ,radioClick(){
        console.log('radioClick : ', this.picked)
      }
      ,radioChange(){
        console.log('radioChange before :', this.picked)
        if(this.picked == 'Two'){
          this.picked= ''
        }
        console.log('radioChange after :', this.picked)
      }
    }
  }
</script>

 

테스트

당연히 될꺼라고 생각했던 방식이 되지 않는다.

지금 소스에서 one은 정상 checked. two은 클릭시 click을 막았다고 생각이 들도록 this.picked'' 로 처리하였다.

그런데 데이터는 초기화 되었지만 radio check는 그대로 유지가 되었다. 데이터를 체크하도록 click 이벤트, change 이벤트, watch까지 로그를 찍어보았다.

// radio one click
radioTest.vue?c821:33 radioClick :  
radioTest.vue?c821:36 radioChange before : One
radioTest.vue?c821:40 radioChange after : One
radioTest.vue?c821:19 watch :  One
// reset
radioTest.vue?c821:29 button :  One
radioTest.vue?c821:19 watch :  
// radio tow click
radioTest.vue?c821:33 radioClick :  
radioTest.vue?c821:36 radioChange before : Two
radioTest.vue?c821:40 radioChange after : 
// reset
radioTest.vue?c821:29 button :  

1. radio one click 후 reset

데이터가 정상으로 변경되고 reset을 누르면 데이터가 초기화 되면서 radio check가 해제된다.

2. radio two click 후 reset

change 메소드에서 데이터를 빈값으로 변경했더니 watch에 잡히지 않는다. reset을 누르면 이미 데이터가 초기화 되어있어서 동일하게 watch가 안잡히고 radio check가 해제 되지 않는다.

 

3차 테스트

소스

<template>
  <div class="text-center">
    <input type="radio" id="one" name="number" value="One" v-model="picked" @click="radioClick" @change="radioChange">
    <label for="one">One</label>
    <br>
    <input type="radio" id="two" name="number" value="Two" v-model="picked" @click="radioClick" @change="radioChange">
    <label for="two">Two</label>
    <br>
    <span>선택: {{ picked }}</span>
    <br>
    <button type="button" @click="reset"> radio data 초기화</button>
  </div>
</template>

<script>
  export default {
    watch:{
      picked(){
        console.log('watch : ', this.picked)
      }
    },
    data(){
      return{
        picked: ''
      }
    },
    methods:{
      reset(){
        console.log('button : ', this.picked)
        this.picked= ''
      }
      ,radioClick(event){
        console.log('radioClick before: ', this.picked)
        event.preventDefault()
        console.log('radioClick after : ', this.picked)
      }
      ,radioChange(event){
        console.log(event)
        console.log('radioChange before :', this.picked)
        if(this.picked == 'Two'){
          this.picked= ''
        }
        console.log('radioChange after :', this.picked)
      }
    }
  }
</script>

 

테스트

 

이번엔 event을 핸들링해서 제어를 했다. radio 버튼을 클릭했을때 가장먼저 event가 발생하는 click 이벤트에서 event.preventDefault() 처리하여 데이터 변경되는 동작을 차단하였다. 클릭시 데이터도 안들어가고 radio도 check가 안되는것을 확인했다. 하지만....

IOS에서 차단 안됨!!!

 

4차 테스트

소스

<template>
  <div class="text-center">
    <input type="radio" id="one" name="number" value="One" v-model="picked" @click="radioClick" @change="radioChange">
    <label for="one">One</label>
    <br>
    <input type="radio" id="two" name="number" value="Two" v-model="picked" @click="radioClick" @change="radioChange">
    <label for="two">Two</label>
    <br>
    <span>선택: {{ picked }}</span>
    <br>
    <button type="button" @click="reset"> radio data 초기화</button>
  </div>
</template>

<script>
  export default {
    watch:{
      picked(){
        console.log('watch : ', this.picked)
      }
    },
    data(){
      return{
        picked: ''
      }
    },
    methods:{
      reset(){
        console.log('button : ', this.picked)
        this.picked= ''
      }
      ,radioClick(event){
        console.log('radioClick before: ', this.picked)
        event.target.checked = false
        console.log('radioClick after : ', this.picked)
      }
      ,radioChange(event){
        console.log(event)
        console.log('radioChange before :', this.picked)
        if(this.picked == 'Two'){
          this.picked= ''
        }
        console.log('radioChange after :', this.picked)
      }
    }
  }
</script>

 

테스트

 콘솔 로그는 event.preventDefault() 와 동일하게 보이지만 event.target.checked = false 으로 check를 false로 바꿔주는 방식으로 처리했다. 해당 소스를 반영해서 확인하니 IOS에서도 정상 동작한다.

 

 

결론

vue radio 의 v-model 과 input radio의 checked 되는 방식이 이해가 되지 않는다.

radio click process

1. input radio의 checked true

2. radio click event 실행(v-model 데이터 변경 전)

3. radio change event 실행(v-model 데이터 변경 후)

 

으로 진행이 되는데 3번에서 v-model을 초기화 해도 input radio의 checked가 초기화(false) 되지 않는다. vue의 장점인 데이터 바인딩으로 radio 버튼 제어를 해보려 했지만 결론은 실패하고 event 핸들링으로 처리하였다. 더 좋은 방법이 있다면 댓글 부탁드립니다.

 

반응형