2

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>
16
  • did you try it with addGrade without () Commented Mar 17, 2020 at 9:01
  • 1
    what error is it giving? Commented Mar 17, 2020 at 9:02
  • 2
    The new Vue part shouldn't be inside the .vue file. Most of the config options that you're passing to the Vue constructor should be inside your component definition instead. I suggest using Vue CLI to build a skeleton project so you can see how things are supposed to be laid out. Commented Mar 17, 2020 at 9:02
  • 1
    may I ask, are you using Vue CDN or VueCLI? Commented Mar 17, 2020 at 10:27
  • 1
    great, that means you're using vue CLI, I'm gonna update my answer soon. Check it out. Commented Mar 17, 2020 at 10:36

4 Answers 4

1

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.

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

1 Comment

Thank it really worked even with vue router. Don't know why but it works. Thanks XD.
0

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;

3 Comments

@JEA Do you want to automatically calculate the average after adding a new grade?
@yes I want to calculate the average after adding a new grade immediately
@JEA add this.calcAvg() after this.newGrade = 0 :)
0

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.

Comments

0

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>

Comments

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.