There is Home.vue and Statistics.vue pages. Home.vue render the TableFields.vue component. At Home.vue there are fields numbers with initial value "3" set on page load. Set interval on calculate function adds numbers every two seconds. How to achieve, that when going from '/' to '/statistics' all the changing should be paused, and on returning back it should be resumed? Bellow each field at home page, already there are buttons that toggle setInterval() function and stop/resume calculations. Basically, when going from "/" to "/statistics" clearInterval() should be triggered that stops the calculations at "/" page. #Saksham TableFields.vue:
<template>
<div>
<table class="table-a">
<tr>
<th>A</th>
<td class="sign">{{ this.randomSign.A }}</td>
<td>{{ initialValue.A }}</td>
<td v-show="this.randomSign.A == '+'">⬆</td>
<td v-show="this.randomSign.A == '-'">⬇</td>
</tr>
</table>
<button #click="toggleIntervalA()">
<span v-show="this.startStop.A">Stop</span>
<span v-show="!this.startStop.A">Start</span>
</button>
<table class="table-b">
<tr>
<th>B</th>
<td class="sign">{{ this.randomSign.B }}</td>
<td>{{ initialValue.B }}</td>
<td v-show="this.randomSign.B == '+'">⬆</td>
<td v-show="this.randomSign.B == '-'">⬇</td>
</tr>
</table>
<button #click="toggleIntervalB()">
<span v-show="this.startStop.B">Stop</span>
<span v-show="!this.startStop.B">Start</span>
</button>
</div>
</template>
<script>
export default {
name: 'TableFields',
props: {
changesA: {
type: Array,
required: false
},
changesB: {
type: Array,
required: false
}
},
data () {
return {
fields: ['A', 'B'],
startStop: {
A: true,
B: true
},
initialValue: {
A: 3,
B: 3
},
randomNumbersArray: [],
randomSign: {
A: '+',
B: '+'
},
signsArray: ['+', '-'],
interval: {
A: null,
B: null
},
localChanges: {
A: [],
B: []
},
timer: undefined
}
},
computed: {},
methods: {
firstObjects () {
for (let i = 0; i < this.fields.length; i++) {
const date = new Date()
const obj = {}
obj.field = this.fields[i]
obj.value = Number((Math.random() * 1 + 1).toFixed(2))
obj.time = date.toLocaleTimeString()
this.changesA.push(obj[0])
this.changesB.push(obj[1])
this.$emit('update:changesA', this.localChanges.A)
this.$emit('update:changesB', this.localChanges.B)
}
},
replaceNumbersArray () { // replace random A, B numbers at time interval
const n1 = Number((Math.random() * 1 + 1).toFixed(2)) // n1 = first number (A)
const n2 = Number((Math.random() * 1 + 1).toFixed(2)) // n2 = second number (B)
this.randomNumbersArray.splice(0, 2, n1, n2)
},
toggleIntervalA () {
this.startStop.A = !this.startStop.A
if (this.startStop.A) {
this.interval.A = setInterval(this.calculationsA, 2000)
} else {
clearInterval(this.interval.A)
}
},
toggleIntervalB () {
this.startStop.B = !this.startStop.B
if (this.startStop.B) {
this.interval.B = setInterval(this.calculationsB, 2000)
} else {
clearInterval(this.interval.B)
}
},
calculationsA () {
this.randomSign.A = this.signsArray[
Math.floor(Math.random() * this.signsArray.length)
]
this.randomSign.A === '+'
? (this.initialValue.A += this.randomNumbersArray[0])
: (this.initialValue.A -= this.randomNumbersArray[0])
const date = new Date()
const newChange = {}
newChange.field = 'A'
newChange.value = this.randomNumbersArray[0]
newChange.time = date.toLocaleTimeString()
this.changesA.push(newChange)
this.$emit('update:changesA', this.localChanges.A)
},
calculationsB () {
this.randomSign.B = this.signsArray[
Math.floor(Math.random() * this.signsArray.length)
]
this.randomSign.B === '+'
? (this.initialValue.B += this.randomNumbersArray[1])
: (this.initialValue.B -= this.randomNumbersArray[1])
const date = new Date()
const newChange = {}
newChange.field = 'B'
newChange.value = this.randomNumbersArray[1]
newChange.time = date.toLocaleTimeString()
this.changesB.push(newChange)
this.$emit('update:changesB', this.localChanges.B)
}
},
mounted () {
this.firstObjects()
setInterval(this.replaceNumbersArray, 2000)
this.initialValue.A = this.$root.initialValue.A || 3
this.initialValue.B = this.$root.initialValue.B || 3
this.timer = setInterval(_ => {
this.interval.A = this.calculationsA
this.interval.B = this.calculationsB
}, 2000)
},
beforeDestroy () {
clearInterval(this.timer)
this.$root.initialValue.A = this.initialValue.A
this.$root.initialValue.B = this.initialValue.B
}
}
</script>
<style lang="scss" scoped>
.table-b {
margin-top: 15px;
}
.sign {
width: 12px;
text-align: center;
}
button {
border: 1px solid transparent;
border-radius: 0;
background-color: #42b983;
color: #ffffff;
margin-top: 7px;
padding: 5px 10px;
&:hover {
opacity: 0.9;
cursor: pointer;
}
}
</style>
Project repo: link
Try using the beforeDestroy() hook to push the counter to either the root component or to vuex store (if you are using one) and fetch the counter in the mounted() hook once you return to the route to resume from there.
and use in your component as
export default {
...
beforeDestroy () {
this.$root.counter = this.counter;
},
mounted () {
this.counter = this.$root.counter || 0;
}
...
}
I have created a sandbox at https://codesandbox.io/s/preserve-timer-state-2osi7 which preserves the state of timer when we move out of the route and starts the timer from where we left.
Comment Notes:
As per you comment, it seems that you are trying to set a property to an object which is undefined. Initially there is no property by the name initialValue in the root component and you are trying to access a property A inside it.
You need to first check if initialValue is defined and then try to check for A
this.initialValue.A = this.$root.initialValue && this.$root.initialValue.A ? this.$root.initialValue.A : 3
Also make sure your data has initialValue as an empty object
initialValue: {}
Related
I have a stopwatch code using Vue 3 and Vuex that has functions that can start, stop and reset.
This is the code :
store/stopwatch/index.js
export default {
state: {
time: "00:10.000",
timeStarted: null,
timeBegan: null,
timeStopped: null,
stoppedDuration: 0,
started: null,
running: false,
temp: {
min: "0",
sec: "0",
ms: "0",
secondsPassed: 0
}
},
actions: {
start({ state, commit, dispatch }) {
if (state.running) return;
if (state.timeBegan === null) {
state.timeBegan = new Date();
}
if (state.timeStopped !== null) {
state.stoppedDuration += new Date() - state.timeStopped;
}
commit("start", {
callback: () => {
dispatch("clockRunning");
}
});
},
async clockRunning({ state, commit, dispatch }) {
let currentTime = new Date();
let timeElapsed = new Date(
currentTime - state.timeBegan - state.stoppedDuration
);
let min = timeElapsed.getUTCMinutes();
let sec = timeElapsed.getUTCSeconds();
let ms = timeElapsed.getUTCMilliseconds();
commit("newTemp", {
key: "secondsPassed",
value: parseInt(Math.abs((state.timeStarted - new Date()) / 1000), 10)
});
if (state.running) {
await dispatch("zeroPrefix", { num: min, digit: 2 }).then(
(zeroPrefixResponse) => {
commit("newTemp", {
key: "min",
value: zeroPrefixResponse
});
}
);
await dispatch("zeroPrefix", { num: sec, digit: 2 }).then(
(zeroPrefixResponse) => {
commit("newTemp", {
key: "sec",
value: zeroPrefixResponse
});
}
);
await dispatch("zeroPrefix", { num: ms, digit: 3 }).then(
(zeroPrefixResponse) => {
commit("newTemp", {
key: "ms",
value: zeroPrefixResponse
});
}
);
state.time =
state.temp.min + ":" + state.temp.sec + "." + state.temp.ms;
}
},
zeroPrefix(context, payload) {
return new Promise((resolve) => {
let zero = "";
for (let i = 0; i < payload.digit; i++) {
zero += "0";
}
resolve((zero + payload.num).slice(-payload.digit));
});
}
},
mutations: {
newTemp(state, payload) {
state.temp[payload.key] = payload.value;
},
addSecondPassed(state, second) {
state.temp.secondsPassed += second;
},
resetSecondPassed(state) {
state.temp.secondsPassed = 0;
},
start(state, payload) {
state.started = setInterval(() => {
payload.callback();
}, 10);
state.running = true;
},
stop(state) {
state.running = false;
state.timeStopped = new Date();
clearInterval(state.started);
},
reset(state) {
state.running = false;
clearInterval(state.started);
state.stoppedDuration = 0;
state.timeBegan = null;
state.timeStopped = null;
state.time = "00:10.000";
}
},
getters: {}
};
App.vue
<template>
<div>
<span class="time">{{ $store.state.stopwatch.time }}</span>
<br />
<button #click="start">Start</button>
<button #click="stop">Stop</button>
<button #click="reset">Reset</button>
</div>
</template>
<script>
export default {
methods: {
start() {
this.$store.dispatch("start");
},
stop() {
this.$store.commit("stop");
},
reset() {
this.$store.commit("reset");
},
},
};
</script>
This is the demo code on codesandbox
What happens with the code above by starting from the 10 seconds and then clicking the start button, seconds starting from the number 0 then 1,2,3. do not continue from number 10.
How to start stopwatch from state time with 10 seconds?
So when click the start button, seconds continue from 10 then to 11,12,13 and so on.
Looks like the issue is that the 10s is not added to the timeBegan. If you subtract the 10 seconds, it should work.
if (state.timeBegan === null) {
state.timeBegan = new Date() - 10_000;
}
On a side note, a mutation should be limited to just the mutation
This code is adding and removing interval from within the mutation and goes against how mutations are supposed to work.
start(state, payload) {
state.started = setInterval(() => {
payload.callback();
}, 10);
state.running = true;
},
stop(state) {
state.running = false;
state.timeStopped = new Date();
clearInterval(state.started);
},
And executing a callback from the mutation is also not good. Not that it won't work, but it's creating a weird state flow that goes against the principles of how the store works.
I know task is super simple. But I do not why it's not working.
Here is a code below how I implemented, as far as I checked this.showStr += this.mainStr.charAt(i) there is no mistake in this part is just something wrong with connection loop and setTimer. Does anybody see an error ?
data(){
return {
mainStr: "Hello, my name is Eldar and I'm web-developer",
showStr: ''
}
},
methods:{
showString() {
for (let i = 0; i < this.mainStr.length; ++i) {
this.delay(i);
}
},
delay(i){
function delay() {
setTimeout(() => {
this.showStr += this.mainStr.charAt(i)
}, 2000)
}
}
},
mounted(){
this.showString();
}
Ohh I'm sorry I published the wrong code. Here is a code which doesnt work
<template>
<p>{{ showStr }}</p>
</template>
<script>
export default {
name: "GreetingTitle.vue",
data(){
return {
mainStr: "Hello, my name is Eldar and I'm web-developer",
showStr: ''
}
},
methods:{
showString() {
for (let i = 0; i < this.mainStr.length; ++i) {
this.delay(i);
}
},
delay(i){
setTimeout(() => {
this.showStr += this.mainStr.charAt(i)
}, 2000)
}
},
mounted(){
this.showString();
}
}
</script>
Your mistake is that you set all timers in one time. You need to set different timers for calling your function time by time with interval, like that:
const mainStr = "Hello, my name is Eldar and I'm web-developer";
let showStr = '';
for (let i = 0; i < mainStr.length; ++i) {
delay(i);
}
function delay(i){
setTimeout(() => {
showStr += mainStr.charAt(i)
console.log(showStr);
}, 300 * i)
}
UP: Vue version (for dummies):
new Vue({
name: "GreetingTitle.vue",
data(){
return {
mainStr: "Hello, my name is Eldar and I'm web-developer",
showStr: ''
}
},
methods:{
showString() {
for (let i = 0; i < this.mainStr.length; ++i) {
this.delay(i);
}
},
delay(i){
setTimeout(() => {
this.showStr += this.mainStr.charAt(i)
}, 300 * i)
}
},
mounted(){
this.showString();
}
}).$mount('#container');
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id='container'>
<p>{{ showStr }}</p>
</div>
I have a vue component responsible for pagination, so that only 20 items are shown per page. Everything is working except for the one value that I need passed down from the parent component, the 'count' value that returns the total number of items.
I use the 'count' value to calculate whether the "Next Page" button is active or not and what the total number of pages should be. Using console.log I can see that the 'count' value returns correctly in to the parent component, but it always comes back as undefined in the child pagination component. Please advise how I can fix this.
(I'm not sure if using watch here is correct; I thought it would solve the problem, but it changed nothing.)
EDIT: I've posted more of both the child and parent component for better context.
Here is the script of the child component:
<script>
export default {
name: 'Pagination',
props: ['count'],
watch: {
count: function (val, oldVal) {}
},
data () {
return {
currentPage: 1,
limit: 20,
paginationVisible: true,
firstPageIsCurrent: true,
prevEllipsisVisible: false,
pageLink1: 2,
pageLink1Visible: true,
pageLink1IsCurrent: false,
pageLink2: 3,
pageLink2Visible: true,
pageLink2IsCurrent: false,
pageLink3: 4,
pageLink3Visible: true,
pageLink3IsCurrent: false,
nextEllipsisVisible: true,
lastPageVisible: true,
lastPageIsCurrent: false,
prevDisabled: true,
nextDisabled: false,
lastPage: 1
}
},
methods: {
handlePrev () {
if (!this.prevDisabled) {
this.currentPage -= 1
this.paginate()
}
},
handleNext () {
if ((this.currentPage * this.limit) < this.count) {
this.currentPage += 1
this.paginate()
}
},
handleFirstPage () {
if (this.currentPage !== 1) {
this.currentPage = 1
this.paginate()
}
},
handlePageLink1 () {
if (this.currentPage !== this.pageLink1) {
this.currentPage = this.pageLink1
this.paginate()
}
},
handlePageLink2 () {
if (this.currentPage !== this.pageLink2) {
this.currentPage = this.pageLink2
this.paginate()
}
},
handlePageLink3 () {
if (this.currentPage !== this.pageLink3) {
this.currentPage = this.pageLink3
this.paginate()
}
},
handleLastPage () {
if (this.currentPage < this.lastPage) {
this.currentPage = this.lastPage
this.paginate()
}
},
paginateAdjust () {
console.log(this.count)
// adjust pagination bar and previous/next buttons
this.nextDisabled = ((this.currentPage * this.limit) >= this.count)
this.prevDisabled = (this.currentPage === 1)
const pageCount = Math.ceil(this.count / this.limit)
// console.log(pageCount + ', cp: ' + this.currentPage)
if (pageCount === 1) {
this.paginationVisible = false
} else {
this.paginationVisible = true
// first page link
this.firstPageIsCurrent = this.currentPage === 1
// previous ellipsis
this.prevEllipsisVisible = this.currentPage > 3 && pageCount > 5
// first page link
this.pageLink2Visible = pageCount > 2
if (this.currentPage < 4) {
this.pageLink1 = 2
} else if ((pageCount - this.currentPage) < 3) {
this.pageLink1 = pageCount - 3
} else {
this.pageLink1 = this.currentPage - 1
}
this.pageLink1IsCurrent = this.pageLink1 === this.currentPage
// second page link
this.pageLink2Visible = pageCount > 3
if (this.currentPage < 4) {
this.pageLink2 = 3
} else if ((pageCount - this.currentPage) < 3) {
this.pageLink2 = pageCount - 2
} else {
this.pageLink2 = this.currentPage
}
this.pageLink2IsCurrent = this.pageLink2 === this.currentPage
// third page link
this.pageLink3Visible = pageCount > 4
if (this.currentPage < 4) {
this.pageLink3 = 4
} else if ((pageCount - this.currentPage) < 3) {
this.pageLink3 = pageCount - 1
} else {
this.pageLink3 = this.currentPage + 1
}
this.pageLink3IsCurrent = this.pageLink3 === this.currentPage
// next ellipsis
this.nextEllipsisVisible = ((pageCount - this.currentPage) >= 3) && pageCount > 5
// last page
this.lastPage = pageCount
this.lastPageIsCurrent = this.currentPage === pageCount
}
},
emitMSQ () {
this.$emit('msq', this.currentPage, this.limit)
},
paginate () {
this.paginateAdjust()
this.emitMSQ()
}
},
created () {
this.paginate()
}
}
</script>
Here is the (relevant) script from the parent component:
export default {
name: 'index',
components: {Pagination},
computed: {
apps () {
return this.$store.state.apps
}
},
data () {
return {
apps: [],
count: 0,
searchAddress: ''
}
},
methods: {
onSearch () {
if (this.searchAddress.length === 12 || this.searchAddress.length === 0) {
this.currentPage = 1
this.makeServerQuery()
}
},
makeServerQuery (cp, pp) {
let queryStr = '?uid=' + this.$auth.user().id + '&cp=' + cp + '&pp=' + pp
if (this.searchAddress.length === 12) {
queryStr += '&se=' + this.searchAddress
}
this.$http.get('/apps' + queryStr).then(res => {
this.apps = res.data.apps
this.count = res.data.count
console.log(this.count + ' msq()')
})
},
The emit, server query, and actual pagination elements all work fine. But my next page button is wrong and the last page button displays NaN because it can't run the correct calculations when count === undefined.
Thanks in advance for the help.
From your comments, it looks like you are not really passing anything to your component's prop.
As #Dan suggested, your count prop is undefined because nothing is being passed to it from the parent. To pass the count data property from the parent to the child you need to use a template binding <child v-bind:count="count"></child> or its shorthand <child :count="count"></child>.
The official documentation is a good starting point for understanding props.
Here's a minimal example.
Vue.config.productionTip = false;
Vue.component('child', {
template: `
<div class="child">
from parent: {{count}}
<br>
<button :disabled="!enableNext" #click="onNext">Next</button>
</div>
`,
props: ['count'],
computed: {
enableNext() {
return this.count && this.count > 0;
}
},
methods: {
onNext() {
console.log('Go to page ' + this.count + 1)
}
}
})
new Vue({
el: '#app',
template: `
<div class="parent">
Parent count: {{ count }}
<child :count="count" />
<br>
<button #click="count++">Increment count</button>
</div>
`,
data:() => ({
count: 0
})
});
div { border: solid 1px black; padding: 1em; }
.child { background: lightgray; }
button:disabled, button[disabled]{
border: 1px solid #999999;
background-color: #cccccc;
color: #666666;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app"></div>
I understand from the caveats portion of the Vue docs that updating a value in an array in the following manner will not work:
this.arr[idx] = newVal
and that one should use splice(). I am using a 2D array to store grid data, and I am having a difficult time updating the value when a cell in the grid is clicked.
Here is my template:
<tr
v-for="(row, rowKey, index) in grid"
:key="rowKey">
<th
class="row-col-label"
>{{rowKey+1}}</th>
<td
v-for="(col, colKey, index) in row"
:key="colKey"
#click="selectCell(rowKey, colKey)"
:class="{'selected' : cellSelected(rowKey, colKey)}"
>
{{col}}
</td>
</tr>
And here is the relevant code for the Vue component:
created () {
this.initColHead()
this.createSpreadSheet()
},
data () {
return {
selected: '',
grid: [],
colHead: [' '],
isSelected: false
}
},
methods: {
initColHead () {
this.colHead.push(...'ABC'.split(''))
},
createSpreadSheet () {
for (let i = 0; i <= 2; i++) {
this.grid[i] = []
for (let j = 0; j <= 2; j++) {
this.grid[i][j] = false
}
}
},
selectCell (row, col) {
this.isSelected = true
console.log(`row ${row} col ${col}`)
this.grid[row].splice(col, 1, true)
for (let i = 0; i <= 2; i++) {
for (let j = 0; j <= 2; j++) {
console.log(this.grid[i][j])
}
}
},
cellSelected (row, col) {
return (this.grid[row][col] === true)
}
}
So I am attempting to add a true value to the cell that is click at the given row col locations provided in the my selectCell method. However, the data in my grid is not updated to reflect the newly added value. How exactly do I update values in a multidimensional array in Vue?
One method that works:
selectCell (row, col) {
//make a copy of the row
const newRow = this.grid[row].slice(0)
// update the value
newRow[col] = true
// update it in the grid
this.$set(this.grid, row, newRow)
},
Here is an example.
console.clear()
new Vue({
el: "#app",
created() {
this.initColHead()
this.createSpreadSheet()
},
data() {
return {
selected: '',
grid: [],
colHead: [' '],
isSelected: false
}
},
methods: {
initColHead() {
this.colHead.push(...'ABC'.split(''))
},
createSpreadSheet() {
for (let i = 0; i <= 2; i++) {
this.grid[i] = []
for (let j = 0; j <= 2; j++) {
this.grid[i][j] = false
}
}
},
selectCell(row, col) {
const newRow = this.grid[row].slice(0)
newRow[col] = true
this.$set(this.grid, row, newRow)
},
cellSelected(row, col) {
return (this.grid[row][col] === true)
}
}
})
.selected {
background-color: green;
}
<script src="https://unpkg.com/vue#2.2.6/dist/vue.js"></script>
<div id="app">
<table>
<tr v-for="(row, rowKey, index) in grid" :key="rowKey">
<th class="row-col-label">{{rowKey+1}}</th>
<td v-for="(col, colKey, index) in row" :key="colKey" #click="selectCell(rowKey, colKey)" :class="{'selected' : cellSelected(rowKey, colKey)}">
{{col}}
</td>
</tr>
</table>
</div>
If I think of something better I'll update later.
The difficulty is that you're building the array in a way that Vue does not make its rows reactive. You could build the array and then assign it to the data item as a whole so that Vue would make it reactive, or you can build the array (at last the rows) using push, which will make them reactive. Then you can modify individual elements using splice. Modifying Bert's example:
console.clear()
new Vue({
el: "#app",
created() {
this.initColHead()
this.createSpreadSheet()
},
data() {
return {
selected: '',
grid: [],
colHead: [' '],
isSelected: false
}
},
methods: {
initColHead() {
this.colHead.push(...'ABC'.split(''))
},
createSpreadSheet() {
for (var i = 0; i <= 2; i++) {
this.grid.push([]);
for (var j = 0; j <= 2; j++) {
this.grid[i].push(false);
}
}
},
selectCell(row, col) {
this.grid[row].splice(col, 1, true);
},
cellSelected(row, col) {
return (this.grid[row][col] === true)
}
}
})
.selected {
background-color: green;
}
<script src="https://unpkg.com/vue#2.2.6/dist/vue.js"></script>
<div id="app">
<table>
<tr v-for="(row, rowKey, index) in grid" :key="rowKey">
<th class="row-col-label">{{rowKey+1}}</th>
<td v-for="(col, colKey, index) in row" :key="colKey" #click="selectCell(rowKey, colKey)" :class="{'selected' : cellSelected(rowKey, colKey)}">
{{col}}
</td>
</tr>
</table>
</div>
I Have a component which parse a json file on mounted phase.
The problem is :
when I click on a button , a send another GET method to get another json file and transmit it to my compoment.
the problem is that the component don't reload itself with the new props and my component display the old values
If someone know how to refresh components , here is my code
<template>
<div class="perturbo">
<div class="col-md-3 btnMenu">
<button v-for="item,index in perturboButtonData.button_list" type="button"
v-bind:style="'background:white'"
class="btn-lg btn-block myBtnClass"
#click="activeButton(index)">
{{item.label}}
</button>
</div>
<div class="col-md-9">
<div class="row">
<graphe
v-for="ana,index in perturboData.ANA"
:key="ana.id"
:data="ana"
:index="index"
type="number"
:timeSpec="perturboData.liste_dates">
</graphe>
</div>
<div class="row">
<graphe
v-for="dig,index in perturboData.DIG"
:key="dig.id"
:index="index"
:data="dig"
type="number"
isDigit="YES"
:timeSpec="perturboData.liste_dates">
</graphe>
</div>
</div>
</div>
</template>
<script>
import axios from 'axios'
import Graphe from './Graphe/Graphe.vue'
export default {
name: 'perturbo',
components : {
'graphe' : Graphe
},
data: function () {
return {
isActivated: false,
perturboData: {},
perturboButtonData: {}
}
},
methods: {
activeButton : function (index) {
console.log(this.perturboButtonData)
axios.get('./static/cgi/' + this.perturboButtonData.button_list[index].link)
.then((response) => {
this.perturboData = response.data;
this.isActivated = true
})
}
},
mounted : function () {
axios.get('./static/cgi/format_json_perturbo.json')
.then((response) => {
this.perturboButtonData = response.data;
})
}
}
</script>
Here is the code of my graphe component
<template>
<div class="graphe">
<vue-chart
:chart-events="chartEvents"
:columns="columns"
:rows="rows"
chart-type="LineChart"
:options="options">
</vue-chart>
</div>
</template>
<script>
export default {
name: 'graphe',
props: {
data: {},
timeSpec : Array,
index: Number,
type: String,
isDigit:String,
},
data: function () {
return {
chartEvents: {
'select': function() {
},
'ready': function() {
}
},
rows: [],
columns: [],
options: {
title: this.data.name,
hAxis: {
},
vAxis: {
ticks : []
},
width: 650,
height: 350,
curveType : 'function'
}
}
},
methods: {
normaliseData : function () {
for (let i = 0; i < this.timeSpec.length; i++) {
this.rows[i] = []
this.rows[i][0] = parseFloat(this.timeSpec[i])
}
this.columns[0] = { 'type': 'number', 'label': 'time' }
for (let i = 0; i < this.data.data.length; i++){
this.columns[i+1] = {'type': this.type ,'label': this.data.data[i].name}
}
for (let i = 0; i < this.timeSpec.length; i++) {
for (let y = 0; y < this.data.data.length; y++) {
this.rows[i][y+1] = parseFloat(this.data.data[y].data[i])
}
}
if (this.isDigit == "YES"){
this.digRow(this.rows)
for (let v = 0; v < this.data.data.length; v ++){
this.options.vAxis.ticks[v] = { v: v, f: this.data.data[v].name}
}
this.options.curveType = ''
}
},
digRow : function (rowTab) {
let newRow = []
let lengthMax = rowTab.length
let rowTmp = []
let index = 0
for (let i = 0; i < lengthMax; i ++){
rowTmp[index] = []
rowTmp[index][0] = rowTab[i][0]
for(let y = 1; y < rowTab[i].length; y ++){
rowTmp[index][y] = rowTab[i][y] + y - 1
}
if (i + 1 !== rowTab.length)
{
newRow = rowTmp[index].slice()
newRow[0] = rowTab[i+1][0]
rowTmp.splice(index+1,0,newRow)
index = index + 2
}
}
this.rows = rowTmp
}
},
mounted: function () {
// // pour les colones
this.normaliseData()
}
}
</script>
EDIT : I know where the problem is :
The data received from the parent is treated just once on the mounted function ! , that's why it doesn't reload on change
Should I use a watcher on props ? how can I do that
Instead of using a method to normalize the data, use a computed property for your rows, columns and options properties. This way, it will update automatically if any of the dependent properties change.
For example, your options property could be a computed property that looks like this:
computed: {
options() {
let options = {
title: this.data.name,
hAxis: {
},
vAxis: {
ticks : []
},
width: 650,
height: 350,
curveType : 'function'
};
if (this.isDigit == "YES"){
this.digRow(this.rows)
for (let v = 0; v < this.data.data.length; v ++){
options.vAxis.ticks[v] = { v: v, f: this.data.data[v].name}
}
options.curveType = ''
}
return options;
}
}
Now, whenever this.data, this.isDigit, or this.rows changes, the options property will update as well.
Your rows and columns properties would look like this:
rows() {
let rows = [];
for (let i = 0; i < this.timeSpec.length; i++) {
rows[i] = []
rows[i][0] = parseFloat(this.timeSpec[i])
for (let y = 0; y < this.data.data.length; y++) {
rows[i][y+1] = parseFloat(this.data.data[y].data[i])
}
}
return rows;
},
columns() {
let columns = [];
columns[0] = { 'type': 'number', 'label': 'time' }
for (let i = 0; i < this.data.data.length; i++) {
columns[i+1] = {'type': this.type ,'label': this.data.data[i].name}
}
return columns;
},
Your changed property won't force view update
To react to state changes, it’s usually better to use a computed
property or watcher.
Try this variant
watch: {
timeSpec(){
//do something
//this.normaliseData()
}
}