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!

  • 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 - https://stackoverflow.com/questions/40915436/vuejs-update-parent-data-from-child-component – stackoverflowusrone Feb 27 '20 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 – Joseph Sjoblom Feb 27 '20 at 16:42

1 Answers1

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>
tony19
  • 125,647
  • 18
  • 229
  • 307
IVO GELOV
  • 13,496
  • 1
  • 17
  • 26
  • 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! – Joseph Sjoblom Feb 27 '20 at 18:50
  • 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. – IVO GELOV Feb 29 '20 at 09:28