Reputation: 75
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
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:
sum
method you reference but haven't createdparseInt
in JavaScript. Use Number()
!).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 templateVue.extend({})
// typically used in typescript apps, for typings inheritance@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
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
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
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