Search code examples
radio-buttonvue.js

How can I unify text that take from multiple group radio button? (vue.js 2)


My vue component like this :

<template>
    <div>
        <div class="col-md-4">
            <ul class="list-unstyled">
                <li><strong>England</strong></li>
                <li>
                    <div class="checkbox">
                        <label>
                            <input type="radio" name="england" class="radio"> Chelsea
                        </label>
                    </div>
                </li>
                <li>
                    <div class="checkbox">
                        <label>
                            <input type="radio" name="england" class="radio"> Mu
                        </label>
                    </div>
                </li>
                <li>
                    <div class="checkbox">
                        <label>
                            <input type="radio" name="england" class="radio"> Arsenal
                        </label>
                    </div>
                </li>
            </ul>
        </div>
        <div class="col-md-4">
            <ul class="list-unstyled">
                <li><strong>Spain</strong></li>
                <li>
                    <div class="checkbox">
                        <label>
                            <input type="radio" name="spain" class="radio"> Madrid
                        </label>
                    </div>
                </li>
                <li>
                    <div class="checkbox">
                        <label>
                            <input type="radio" name="spain" class="radio"> Barcelona
                        </label>
                    </div>
                </li>
                <li>
                    <div class="checkbox">
                        <label>
                            <input type="radio" name="spain" class="radio"> Atletico
                        </label>
                    </div>
                </li>
            </ul>
        </div>
        <div class="col-md-4">
            <ul class="list-unstyled">
                <li><strong>Italy</strong></li>
                <li>
                    <div class="checkbox">
                        <label>
                            <input type="radio" name="italy" class="radio"> Juve
                        </label>
                    </div>
                </li>
                <li>
                    <div class="checkbox">
                        <label>
                            <input type="radio" name="italy" class="radio"> Milan
                        </label>
                    </div>
                </li>
                <li>
                    <div class="checkbox">
                        <label>
                            <input type="radio" name="italy" class="radio"> Inter
                        </label>
                    </div>
                </li>
            </ul>
        </div>
        <span id="result-select">Result</span>
    </div>
</template>

<script>
    export default {
        props: ['...'],
        ...
    }
</script>

My javascript code like this :

$('input[type="radio"]').click(function(){
    var $radio = $(this);
    var name = $(this).prop("name");

    // if this was previously checked
    if ($radio.data('waschecked') == true)
    {
        $radio.prop('checked', false);
        $radio.data('waschecked', false);
        $('#result-select').text('');
    }
    else{
        $radio.data('waschecked', true);
        $(`input[name=${name}]:not(:checked)`).data('waschecked', false);
        $('#result-select').text(txt);
    }

    let output = [];
    var txt;
    $('input[type="radio"]:checked').each( function() {
            txt = $(this).parent().text();
            output.push(txt);
    });
    $('#result-select').text(output.join(' - '));
});

I still use javascript to unify each selected radio button group. This javascript code is working fine. But I want to change it using vue component. So there is no javascript code. But I am still confused

I will explain the plot first

I want to :

If I select chelsea, madrid and juve the result like this :

Chelsea - Madrid - Juve

If I select chelsea and madrid the result like this :

Chelsea - Madrid

So if I check radio button, it display the text. If I uncheck radio button, it not display the text

How can I do it in vue component?

Update :

The radio button can be unchecked

For example :

If I select chelsea, madrid and juve the result like this :

Chelsea - Madrid - Juve

Then I uncheck madrid, the result like this :

Chelsea - Juve


Solution

  • Any time you need a value based on other values, you should look at using a computed. In this case, a computed that goes through the country data and picks out the selected city names and returns them as a list.

      computed: {
        selecteds() {
          return this.countries
            .map(c => c.selected)
            .filter(s => s);
        }
      },
    

    Check-and-uncheck functionality is supplied by v-model on the radio inputs. If the value of what is bound to v-model matches the value bound to value, the button is checked; if not, not.

    I used a settable computed to handle the case where you're clicking an already-clicked button. If it is already selected, set the value to null to unselect it. Because I'm in a component, "set the value to null" is done by emitting an event that the parent uses to set the value.

    computed: {
        proxySelected: {
          get() {
            return this.data.selected;
          },
          set(newValue) {
            this.$emit('update', this.data.name, this.data.selected === newValue ? null : newValue);
          }
        }
      }
    

    function countryData(name, cities) {
      return {
        name,
        cities,
        selected: null
      };
    }
    
    new Vue({
      el: '#app',
      data: {
        countries: [
          countryData('England', ['Chelsea', 'MU', 'Arsenal']),
          countryData('Spain', ['Madrid', 'Barcelona', 'Atletico']),
          countryData('Italy', ['Juve', 'Milan', 'Inter'])
        ]
      },
      computed: {
        selecteds() {
          return this.countries
            .map(c => c.selected)
            .filter(s => s);
        }
      },
      methods: {
        update(countryName, newSelectedValue) {
          this.countries.find(c => c.name === countryName).selected = newSelectedValue;
        }
      },
      components: {
        country: {
          template: '#country-template',
          props: ['data'],
          data() {
            return {
              checked: []
            };
          },
          computed: {
            proxySelected: {
              get() {
                return this.data.selected;
              },
              set(newValue) {
                this.$emit('update', this.data.name, this.data.selected === newValue ? null : newValue);
              }
            }
          }
        }
      }
    });
    .list-unstyled {
      list-style: none;
    }
    <script src="//cdnjs.cloudflare.com/ajax/libs/vue/2.3.4/vue.min.js"></script>
    <div id="app">
      <country v-for="country in countries" :data="country" @update="update" :key="country.name"></country>
      <div>{{selecteds.join(' - ')}}</div>
    </div>
    
    <template id="country-template">
      <div class="col-md-4">
        <ul class="list-unstyled">
          <li><strong>{{data.name}}</strong></li>
          <li v-for="city in data.cities">
            <div class="checkbox">
              <label>
                <input type="radio" :name="data.name" class="radio" :value="city" v-model="proxySelected">
                {{city}}
              </label>
            </div>
          </li>
        </ul>
      </div>
    </template>