JEA
JEA

Reputation: 75

(VueJs) I can't use methods in vuejs?

Hi I'm trying to make a website where I have a home and a "Brazil" component. I'm using vue router to switch between home and Brazil. In Brazil there is a calculator but I cant use the methods used in the script tag. The calculator should ask for a grade input and then calculate the Average of it when the user clickes on Average. The calculation is correct. The buttons don't work. Does annyone know what the problem is? Here is the code:

<template>

  <div>
    Brazil
    <h2>Grade-Calculator </h2>
    <div id="calculator">
      <ul>
        <li v-for="(g,idx) in grades" :key="idx">{{idx+1}}. Grade : {{g}}</li>
      </ul>
      <div>
        <label>New Grade: </label>
        <input type="text" v-model="newGrade" />
        <button v-on:click="addGrade()">Ok</button>
      </div>
      <br>
      <div>
        <button v-on:click="calcAvg()">Average</button>
        <p>Average: {{ sum }}</p>
      </div>
  </div>
  </div>
</template>

<script>
import Vue from 'vue'
export default {
  name: "Brazil",
  props: {}
};
new Vue({
    el: '#calculator',
    data: {
      grades: [],
      newGrade: 0,
      avg: 0
      //TEST
    },
    methods: {
      addGrade: function () {
        this.grades.push(this.newGrade)
        this.newGrade = 0
      },
      calcAvg: function () {
        let sum = 0;
        for (var i = 0; i < this.grades.length; i++) {
          let zahl = parseInt(this.grades[i]);
          sum = sum + zahl;
        }
        //calculate average and print it
        console.log(sum)
        console.log(this.grades.length)
        return sum / this.grades.length;
      }
    }
  })
</script>

Upvotes: 2

Views: 1060

Answers (4)

tao
tao

Reputation: 90287

You're trying to use two different patterns at the same time, on the same component! One is SFC (single file component) and the other is rendering a new Vue instance which replaces a particular element in your existing DOM.

From what you posted, it's unclear how you're using this in home. However, you seem to be exporting a very basic object (with a name and empty props) then you are creating a new instance of Vue inside your already exported SFC.

Vue is very flexible and you might get it to work, but it's likely a complication you don't really want.

I made a few minor other fixes:

  • i replaced the average function
  • i removed the sum method you reference but haven't created
  • fixed type casting (don't use parseInt in JavaScript. Use Number()!).
  • a few more details I can't remember

Here's how your component would get used with Vue.component() declaration:

Vue.config.productionTip = false;
Vue.config.devtools = false;
Vue.component('Calculator', {
  template: `
    <div>
      <h2>Grade-Calculator</h2>
      <div>
        <ul>
          <li v-for="(g,key) in grades" :key="key">{{key+1}}. Grade : {{g}}</li>
        </ul>
        <div>
          <label>New Grade:</label>
          <input type="text" v-model="newGrade">
          <button @click="addGrade()">Add</button>
        </div>
        <br>
        <div>
          <p>Average: {{ average }}</p>
        </div>
      </div>
    </div>
  `,
  name: 'Calculator',
  data: () => ({
    grades: [],
    newGrade: 0,
    avg: 0
    //TEST
  }),
  computed: {
    average() {
      return this.grades.length ? `${this.calcAvg(this.grades)}` : "n/a";
    }
  },
  methods: {
    calcAvg(grades) {
      return grades.reduce((a, b) => Number(a) + Number(b), 0) / grades.length;
    },
    addGrade() {
      this.grades.push(this.newGrade);
      this.newGrade = 0;
    }
  }
});
new Vue({
  el: '#app'
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
  <Calculator />
</div>

And here's how you'd use SFC: https://codesandbox.io/s/zealous-ellis-0m0p2


There are more ways to create components in Vue:

  • new Vue({ el: '#elId' }) // replaces the element, using its contents as template
  • Vue.extend({}) // typically used in typescript apps, for typings inheritance
  • declaring them as classes with @Component decorator, if using the vue-class-component plugin (it's just a wrapper around Vue.extend(), at core).

There might be more, but the ones mentioned above are the most common.

Upvotes: 1

Olawale Oladiran
Olawale Oladiran

Reputation: 631

Since you're using vueCLI, you don't need to declare your app element again, as it would have been declared for you in the "App.vue" component inside "src" directory. Change your script to this:

<script>
    export default {
        name: "Brazil",
        props: {},

        data: {
           return {
              grades: [],
              newGrade: 0,
              avg: 0,
              sum: 0,
              //TEST
           }
        },
        methods: {
          addGrade: function () {
            this.grades.push(this.newGrade)
            this.newGrade = 0
          },
          calcAvg: function () {
            let sum = 0;
            for (var i = 0; i < this.grades.length; i++) {
              let zahl = parseInt(this.grades[i]);
              sum = sum + zahl;
            }
            //calculate average and print it
            console.log(sum)
            console.log(this.grades.length)
            this.sum = sum / this.grades.length;
          }
        }
    };
</script>

Upvotes: 0

Rijosh
Rijosh

Reputation: 1554

You can directly add the data and methods sections in the export default section like follows.

export default {
  name:"Brazil",
  props:[], // add properties here
  data:()=>{
      return {
         // create your data variables here
      }
  },
  methods:{
     // create your methods here
  }
}

In the Vue.js component structure, the html template part is associated with the export default next to it. And when you're using a method inside the template, it will check the method in the methods section of export default part.

Upvotes: 0

lucas
lucas

Reputation: 1145

Some small adjustments would do the trick.

data: {
  grades: [],
  newGrade: 0,
  avg: 0,
  sum: 0, // Add this
},

Change this:

return sum / this.grades.length;

to this:

this.sum = sum / this.grades.length;

Upvotes: 0

Related Questions