I have a problem with v-if in combination with watchers and data in vue. I have the following SFC:
<script lang="ts">
// imports ...
export default defineComponent({
data() {
return {
store,
api: new Api(Constants.baseUrl),
game: null as (Game | null),
playerIcons: Constants.playerIcons,
gameId: this.$route.params.id as string,
poller: null as number | null,
whoseTurn: null as Color | null,
};
},
methods: {
async pollGame(): Promise<void> {
try {
this.game = await this.api.readGame(this.gameId);
// snip
} catch (error) {
alert(error);
}
},
colorToNotation(color: Color): string | null {
if (color === Color.A) {
return "A";
} else if (color === Color.B) {
return "B";
} else if (color === Color.C) {
return "C";
} else if (color === Color.D) {
return "D";
}
return null;
},
notationToColor(notation: string): Color | null {
if (notation === 'a') {
return Color.A;
} else if (notation === 'b') {
return Color.B;
} else if (notation === 'c') {
return Color.C;
} else if (notation === 'd') {
return Color.D;
}
return null;
}
},
async mounted() {
this.pollGame();
this.poller = setInterval(this.pollGame, Constants.pollingInterval);
},
unmounted() {
if (this.poller) {
clearInterval(this.poller!);
}
},
watch: {
'game.notation'(newValue) {
// snip
const playerNotation: string = newValue[newValue.length - 1];
let previousTurn: Color | null = this.whoseTurn;
this.whoseTurn = this.notationToColor(playerNotation);
console.log(`Set turn from ${this.colorToNotation(previousTurn!)} to ${this.colorToNotation(this.whoseTurn!)}`);
}
}
// snip
});
</script>
<template>
<!-- snip -->
<div v-if="game">
<div id="whose-turn" v-if="whoseTurn">
Turn:
<img class="player-icon" :src="playerIcons.get(whoseTurn)" />
{{ game.getPlayer(whoseTurn)!.name }}
</div>
<div v-else>
No turn
</div>
<!-- snip -->
</div>
<!-- snip -->
</template>
The game engine gives back a notation in which the last letter indiciates whose turn it is: 'a', 'b', 'c' or 'd' (in this order). Unfortunately, whenever player a is at turn, the v-if goes to false and "No turn" is displayed. However, the logs indicate that when the game is read from the server, it is set to 'A' and is never null again:
Console log:
Set turn from null to A
Set turn from A to B
Set turn from B to C
Set turn from C to D
Set turn from D to A
Set turn from A to B
Set turn from B to C
Set turn from C to D
Set turn from D to A
Set turn from A to B
Set turn from B to C
Set turn from C to D
Set turn from D to A
...
While I see in the browser (listed here all at once instead of one at a time in the browser):
No turn
Turn: B
Turn: C
Turn: D
No turn
Turn: B
Turn: C
Turn: D
No turn
Turn: B
Turn: C
Turn: D
...
The logs show that variable this.whoseTurn has the correct value; but infortunately the v-if seems to remember that this.whoseTurn is null from the first milliseconds when waiting on the game data from the server, and keeps associating turn A with null?
This is really confusing, what is going on?
Colordefined? Could be thatColor.A==null. In that casecolorToNotation()would still return "A" for your log statements but result false forv-if="whoseturn"export enum Color {A,B,C,D}. If I addconsole.log(playerNotation, this.whoseTurn);beforeconsole.log(`Set turn from ${this.colorToNotation(previousTurn!)} to ${this.colorToNotation(this.whoseTurn!)}`);I get the following:a 0 b 1 c 2 d 3 a 0 b 1 c 2 d 3 a 0.