0

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?

2
  • How is Color defined? Could be that Color.A == null. In that case colorToNotation() would still return "A" for your log statements but result false for v-if="whoseturn" Commented Sep 5, 2022 at 16:33
  • Color is just an enum: export enum Color {A,B,C,D}. If I add console.log(playerNotation, this.whoseTurn); before console.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. Commented Sep 6, 2022 at 5:03

1 Answer 1

2

By answering the comment of @yoduh I've fumbled on the solution. The enum does not have values assigned:

export enum Color {
    A,
    B,
    C,
    D,
}

So the default value for Color.A is 0 which the v-if statement evaluates as false. This is why everytime player A plays, it's turn is displayed as "No turn".

I've fixed it like this:

export enum Color {
    A = 1,
    B,
    C,
    D,
}
Sign up to request clarification or add additional context in comments.

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.