3

I am trying to apply an active class to a list item in a template component when it is clicked upon, this should be exclusive and remove the class from all other list items.

I have tried passing through a new data object on click and referencing that, I have even used the example in the official documentation to no avail, I have no idea why it isn't working.

Vue.component('delivery-options', {
      props: ['deliveries'],
      template: '<li><p><strong>{{ deliveries.price }}</strong>{{ deliveries.title }}</p><p>{{ deliveries.desc }}</p></li>'
    })
    Vue.component('ledger', {
      props: ['values'],
      template: '<li><p>{{ values.title }}<span>{{ values.price }}</span></p></li>'
    })
    var checkout = new Vue({
      el: '#checkout-app',
      data: {
        deliveryList: [
          { id: 0, price: '£3.99 ', title: 'Home delivery', desc: 'Lorem ipsum dolor sit amet.' },
          { id: 1, price: 'Free ', title: 'Store collection', desc: 'Lorem ipsum dolor sit amet.' },
          { id: 2, price: '£5.99 ', title: 'Precise delivery', desc: 'Lorem ipsum dolor sit amet.' }
        ],
        valuesList: [
          { id: 0, price: '£1233.99', title: 'Order value', desc: 'Lorem ipsum dolor sit amet.' },
          { id: 1, price: '£3.99', title: 'Delivery', desc: 'Lorem ipsum dolor sit amet.' },
          { id: 2, price: '£5.99', title: 'Total', desc: 'Your total including delivery.' }
        ]
      }
    })
ul {
  padding: 0;
}

ul li {
  list-style-type: none;
}

.delivery-options li {
  padding: 1rem;
  margin: 1rem;
  border-radius: 3px;
  border: 1px solid grey;
}

.ledger {
  padding: 1rem;
  margin: 1rem;
  border-radius: 3px;
  border: 1px solid grey;
}
<script src="https://unpkg.com/vue"></script>
<div id="checkout-app">
    <ul class="delivery-options">
      <delivery-options
        v-for="option in deliveryList"
        v-bind:deliveries="option"
        v-bind:key="option.id">
      </delivery-options>
    </ul>
    <ul class="ledger">
      <ledger
        v-for="value in valuesList"
        v-bind:values="value"
        v-bind:key="value.id">
      </ledger>
    </ul>
  </div>

1 Answer 1

2

You would need to do something like this:

console.clear()

Vue.component('delivery-options', {
      props: ['deliveries', "isActive"],
      template: `<li @click="$emit('set-active', deliveries)" :class="{active: isActive}"><p><strong>{{ deliveries.price }}</strong>{{ deliveries.title }}</p><p>{{ deliveries.desc }}</p></li>`
    })
    Vue.component('ledger', {
      props: ['values'],
      template: '<li><p>{{ values.title }}<span>{{ values.price }}</span></p></li>'
    })
    var checkout = new Vue({
      el: '#checkout-app',
      data: {
        activeDelivery: null,
        deliveryList: [
          { id: 0, price: '£3.99 ', title: 'Home delivery', desc: 'Lorem ipsum dolor sit amet.' },
          { id: 1, price: 'Free ', title: 'Store collection', desc: 'Lorem ipsum dolor sit amet.' },
          { id: 2, price: '£5.99 ', title: 'Precise delivery', desc: 'Lorem ipsum dolor sit amet.' }
        ],
        valuesList: [
          { id: 0, price: '£1233.99', title: 'Order value', desc: 'Lorem ipsum dolor sit amet.' },
          { id: 1, price: '£3.99', title: 'Delivery', desc: 'Lorem ipsum dolor sit amet.' },
          { id: 2, price: '£5.99', title: 'Total', desc: 'Your total including delivery.' }
        ]
      },
    })
ul {
  padding: 0;
}

ul li {
  list-style-type: none;
}

.delivery-options li {
  padding: 1rem;
  margin: 1rem;
  border-radius: 3px;
  border: 1px solid grey;
}

.ledger {
  padding: 1rem;
  margin: 1rem;
  border-radius: 3px;
  border: 1px solid grey;
}

.active {
  color: red
}
<script src="https://unpkg.com/vue"></script>
<div id="checkout-app">
    <ul class="delivery-options">
      <delivery-options
        v-for="option in deliveryList"
        v-bind:deliveries="option"
        v-bind:key="option.id"
        v-bind:is-active="option === activeDelivery"
        v-on:set-active="v => activeDelivery = v">
      </delivery-options>
    </ul>
    <ul class="ledger">
      <ledger
        v-for="value in valuesList"
        v-bind:values="value"
        v-bind:key="value.id">
      </ledger>
    </ul>
  </div>

Basically, track which delivery is active using a data property, then set the class in the component based on whether it is the active delivery or not. In order to set the active delivery on click, the component needs to emit an event letting the parent know which delivery was clicked.

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

1 Comment

amazing thank you, I had something similar before but it was only tracking clicks on the parent, therefore it wasn't actually updating anything at all

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.