0

I am looking to extend a vue-toggle component I found to add a boolean value. I am trying to add ability to hide/show an element based on the boolean prop.

Here is my html code:

<div class="container" id="app">
  <div class="row">
<div class="col-xs-3 col-sm-4 col-md-5 col-lg-6">
  <img src="https://images-na.ssl-images-amazon.com/images/I/81UxhkSlBjL._UX466_.jpg" alt="" class="img-responsive" />
</div>
<div class="col-xs-9 col-sm-8 col-md-7 col-lg-6 options">
  <fieldset class="form-group">
    <legend class="sr-only">Style</legend>
    <div class="form-group">
      <vue-toggle :values="styles" :boolean="showVNeck" :selected.sync="style" default="crew"></vue-toggle>
    </div>
  </fieldset>
    <div><span v-if="showVNeck">V Neck</span><span v-else>Crew Neck</span> Selected</div>
</div>
  </div>
</div>

<template id="vue-toggle">
  <div class="btn-group">
    <button type="button" 
  v-for="(val, key) in values"
  @click="changeSelectVal(key, boolean)"
  :class="['btn', { 'btn-primary': selected === key, 'btn-default': selected !== key }]"
  >{{ val }}</button>
  </div>
</template>

Here is my javascript:

        var Toggle = Vue.extend({
    template: '#vue-toggle',
    props: ['values','selected','boolean','default'],
    mounted: function () {
        this.selected = this.default;
    },
    methods: {
        changeSelectVal: function(val, boolean) {
        this.selected = val;
        this.boolean = !this.boolean;
        }
    }
    });
    Vue.component('vue-toggle', Toggle);

    new Vue({
    el: '#app',
    data: {
        style: '',
        showVNeck: false,
        styles: {
        'crew': 'Crew Neck',
        'vneck': 'V-Neck',
        }
    }
    });

Here is a codepen to share: https://codepen.io/mujaji/pen/YzXVqaL

I think I am just overlooking something and looking for assistance.

Cheers!

2
  • 1
    Please mention clearly what is expected output and what is not working. As far as I understand, you are just updating boolean in the vue-toggle component which is working. But note that showVNeck in parent will not automatically update based on that, see this for more - stackoverflow.com/questions/40915436/… Commented Feb 27, 2020 at 16:39
  • Expected output is when I click the button group it will toggle the boolean value, in this case showVNeck, from true to false Commented Feb 27, 2020 at 16:42

1 Answer 1

1

The .sync modifier requires that your child emits events of the type update:myPropName instead of directly mutating the prop - look at the documentation:

var Toggle = Vue.extend({
  template: '#vue-toggle',
  props: ['values','selected','boolean','default'],
  mounted: function () {
    this.$emit('update:selected',this.default);
  },
  methods: {
    changeSelectVal: function(val, boolean) {
      this.$emit('update:selected',val);
      this.$emit('update:boolean',!this.boolean);
    }
  }
});
Vue.component('vue-toggle', Toggle);

new Vue({
  el: '#app',
  data: {
    style: '',
    showVNeck: false,
    styles: {
      'crew': 'Crew Neck',
      'vneck': 'V-Neck',
    },
  },
      methods:
    {
      updateVNeck(newValue)
      {
        this.showVNeck = newValue;
      }
    }
});
body {
  background-color: #5c4084;
  padding: 50px;
}
.container {
  background-color: #fff;
  padding-top: 40px;
  padding-bottom: 80px;
  border-radius: 8px;
}
.heading 
  h1 {
    color: #fff;
    font-size: 4rem;
    font-weight: 900;
    margin: 0 0 5px 0;
    background: -webkit-linear-gradient(#fff, #999);
    -webkit-background-clip: text;
    -webkit-text-fill-color: transparent;
    text-align: center;
  }
.heading  h4 {
    color: #5c3d86;
    font-size: 24px;
    font-weight: 400;
    text-align: center;
    margin: 0 0 35px 0;
  }


  .options {
    padding-top: 80px;
  }

.btn{
  outline: none !important;
}
.btn.btn-primary {
  background-color: #5c4084;
  border-color: #5c4084;
  outline: none;
  }
  .btn.btn-primary:hover {
    background-color: #5c4084;
    border-color: #5c4084;
  }
  .btn.btn-primary:active, .btn.btn-primary:focus {
    background-color: #5c4084;
    border-color: #5c4084;
  }

.btn.btn-default:hover {
    background-color: #5c4084;
    border-color: #5c4084;
    color: #fff;
  }
  .btn.btn-default:active, .btn.btn-default:focus {
    background-color: #5c4084;
    border-color: #5c4084;
    color: #fff;
  }
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.min.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.6.3/css/font-awesome.min.css">

<div class="container" id="app">
    
  <div class="row">
    <div class="col-xs-3 col-sm-4 col-md-5 col-lg-6">
      <img src="https://images-na.ssl-images-amazon.com/images/I/81UxhkSlBjL._UX466_.jpg" alt="" class="img-responsive" />
    </div>
    <div class="col-xs-9 col-sm-8 col-md-7 col-lg-6 options">
      
      

      <fieldset class="form-group">
        <legend class="sr-only">Style</legend>
        <div class="form-group">
          <vue-toggle :values="styles" :boolean.sync="showVNeck" :selected.sync="style" default="crew"></vue-toggle>
        </div>
      </fieldset>
<div><span v-if="showVNeck">V Neck</span><span v-else>Crew Neck</span> Selected</div>
      
      
    </div>
  </div>
  
</div>

<template id="vue-toggle">
  <div class="btn-group">
    <button type="button" 
      v-for="(val, key) in values"
      @click="changeSelectVal(key, boolean)"
      :class="['btn', { 'btn-primary': selected === key, 'btn-default': selected !== key }]"
      >{{ val }}</button>
  </div>
</template>

Sign up to request clarification or add additional context in comments.

2 Comments

Thank you @ivo-gelov. Didnt realize I need to work with mounted() in order to get it working properly. Thought I could just pass a value and it would toggle based on true/false. I appreciate you explaining. Cheers!
I think you misunderstood my answer. The problem was not the mounted() hook - the problem was that you mutate the props in the child. This does not work (as you have noticed) - your child instead has to emit an event and the parent should handle the event and change the value which will then be propagated to the child through the relevant prop. The .sync modifier just provides a convenient shorthand for this - but you have to emit an event with the proper name.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.