GrandMaster
GrandMaster

Reputation: 23

How to access a function variable as a data property in Vue

I have this accordion with three arrows. When you click on the arrow it should transform 180deg. I want to have a function that takes the parameter set in the function and tells the data property to change to zero.

I've tried

let vm = this;
vm.$data.arrowOne = 0;
And this[arrow] = 0,
And this.arrow = 0

And it's not working.

Here is my code.

 <div class="uk-accordion-ekstra">
  <ul uk-accordion="multiple: true">
    <li>
        <a @click="rotate(arrowOne)" class="uk-accordion-title" href="#">Headline
          <img :style="{ transform: 'rotate('+ arrowOne + 'deg)'}" src="IMGSRC"></a>

          <div class="uk-accordion-content">
            <p>TEXT</p>
        </div>
    </li>
    <li>
        <a @click="rotate(arrowTwo)" class="uk-accordion-title" href="#">Headline
          <img :style="{ transform: 'rotate('+ arrowTwo + 'deg)'}" src="IMGSRC"></a>
        <div class="uk-accordion-content">
            <p>TEXT</p>
        </div>
    </li>
    <li>
        <a @click="rotate(arrowThree)" class="uk-accordion-title" href="#">Headline
          <img :style="{ transform: 'rotate('+ arrowThree + 'deg)'}" src="IMGSRC"></a>
        <div class="uk-accordion-content">
            <p>TEXT</p>
        </div>
    </li>
  </ul>
</div>

And VUE

 new Vue({
  el: '.uk-accordion-ekstra',
  data: { 
    arrowOne: 180,
    arrowTwo: 180,
    arrowThree: 180
  },
  methods: {
    arrow: function(arrow) {
      if(this.arrow = 0) {
        return this.arrow = 180;
      }
    }
  }
});

I have succesfully managed to do it with a switch. But it aren't as beautiful. And im unsure of what i don't get. So help is appreciated.

Upvotes: 0

Views: 257

Answers (1)

muka.gergely
muka.gergely

Reputation: 8329

You have a structural and a scope problem.

  1. You are referencing this.arrow in a method called arrow, and you pass an argument called arrow - try to differentiate with the names, or you can get messed up
  2. You are repeating stuff that you don't need to. Vue is great for creating components for the smallest of elements - you can use it to make your code shorter, more readable and more effective.

The snippet below makes everything easier:

  • you have one arrow per component, and if you solve the rotation problem in one place, then it's solved everywhere, and the arrow referenced always connects to the component you edit
  • you can encapsulate your arrow rotation into one component - no need to "litter" the Vue instance with such small animation
  • I added @click.prevent that's like preventDefault(), so there won't be a jump to the top when you click an <a></a>

Vue.component('accordion', {
  props: ['title', 'text'],
  template: '<div><a @click.prevent="rotateArrow()" class="uk-accordion-title" href="#">{{ title }} <i class="fa fa-arrow-circle-o-up" :style="`transform: rotate(${rotation}deg)`"></i></a><div class="uk-accordion-content"><p>{{ text }}</p></div></div>',
  data() {
    return {
      rotation: 0
    }
  },
  methods: {
    rotateArrow() {
      this.rotation = !this.rotation ? 180 : 0
    }
  }
})

new Vue({
  el: '.uk-accordion-ekstra',
  data: {
    accordionItems: [{
        title: 'Headline 1',
        text: 'Text 1'
      },
      {
        title: 'Headline 2',
        text: 'Text 2'
      },
      {
        title: 'Headline 3',
        text: 'Text 3'
      },
    ]
  }
});
<link href="https://stackpath.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet" integrity="sha384-wvfXpqpZZVQGK6TAh5PVlGOfQNHSoD2xbE+QkPxCAFlNEevoEH3Sl0sibVcOQVnN" crossorigin="anonymous">
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>

<div class="uk-accordion-ekstra">
  <ul uk-accordion="multiple: true">
    <li v-for="accordionItem in accordionItems" :key="accordionItem.title">
      <accordion :title="accordionItem.title" :text="accordionItem.text"></accordion>
    </li>
  </ul>
</div>

Upvotes: 2

Related Questions