The v-if directive doesn't get updated properly when a watcher modifies an enum data variable

I'm encountering an issue with the usage of v-if alongside watchers and data in Vue. Below is a snippet from my Single File Component (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 scenario revolves around the game engine returning a notation where the last letter represents whose turn it is, for instance 'a', 'b', 'c' or 'd'. Strangely, when player 'a' takes their turn, the v-if evaluates to false causing "No turn" to be displayed. However, logs clearly indicate that upon fetching game data from the server, it's set to 'A' and never becomes 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
...

However, what's rendered in the browser is (listed here all at once instead of one at a time):

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 affirm that the variable this.whoseTurn holds the correct value, yet mysteriously the v-if seems to retain the initial null value of this.whoseTurn while waiting on game data from the server, hence associating turn A with null.

This situation is quite perplexing, any insights on what might be occurring?

Answer №1

After addressing @yoduh's comment, I stumbled upon the solution. The enum was missing values:

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

Due to this, Color.A defaulted to 0, causing the v-if statement to evaluate as false. This resulted in player A always displaying as "No turn".

To correct this issue, I made the following adjustment:

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

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Tips for refreshing the value of a dependency injection token

When using Angular dependency injection, you have the ability to inject a string, function, or object by using a token instead of a service class. To declare it in my module, I do this: providers: [{ provide: MyValueToken, useValue: 'my title value& ...

No default export found in Module: TypeScript RestAPI

The word controller is showing a red underline when I use import controller from '../controllers/test.controller'; In my typescript rest api application, the structure looks like this... project structure I am puzzled by the red line under cont ...

The various types of Angular 2 FormBuilders

As I delved into learning Angular 2, I initially came across ngModel, and later discovered FormGroup/FormBuilder which seemed more suitable for handling complex forms. However, one downside that caught my attention was that by using FormBuilder, we sacrifi ...

Having an issue with Vue.js displaying a blank page post running `npm run serve` and configuring it with IIS

Error Message on Empty Page Despite not using History mode and trying numerous solutions, the issue remains unsolved. I initialized a vuejs project with the command vue create my_project. Following that, I attempted to run npm run serve, which successful ...

Generating Pulumi Outputs for exporting as an external configuration file

I am currently utilizing Cloudrun in GCP and am interested in summarizing the created APIs with API Gateway. To achieve this, a Swagger/OpenAPI v2 document needs to be generated containing the google-generated URLs for the Cloudrun Services. How can I ext ...

When working with Visual Studio and a shared TypeScript library, you may encounter the error message TS6059 stating that the file is not under the 'rootDir'. The 'rootDir' is expected to contain all source files

In our current setup with Visual Studio 2017, we are working on two separate web projects that need to share some React components built with TypeScript. In addition, there are common JavaScript and CSS files that need to be shared. To achieve this, we hav ...

Reset the select boxes when a button is clicked

I'm currently utilizing Devextreme within my Angular application, and I have three dx-selectbox elements in the component. I am attempting to clear all three dropdown selections when clicking a "clear" button. Unfortunately, I am unable to find a way ...

Is there a way to trigger the click event in the week view of an Angular 2+ calendar?

https://i.sstatic.net/Vx2x8.png HTML Templates <mwl-calendar-week-view [viewDate]="viewDate" [refresh]="refresh" (click)="weekDayClick($event)"> </mwl-calendar-week-view> In the component file weekDayCl ...

The type 'RefObject<HTMLDivElement>' cannot be matched with type 'RefObject<HTMLInputElement>' in this context

Encountered an error message: Issue with assigning types: Type '{ placeholder: string | undefined; autoComplete: string | undefined; "data-testid": string | undefined; onChange?: ChangeEventHandler<HTMLInputElement | HTMLTextAreaElement&g ...

Is there a way to execute v-for once the created() lifecycle hook has finished running?

In my current project, I am faced with the challenge of including avatars in notifications. Despite my efforts, I have not been able to solve this issue independently. The Vue.js template below demonstrates how I have attempted to add avatars to each notif ...

How to Utilize Vue and Checkboxes for Filtering a List?

My current challenge involves filtering a list of posts based on userId using checkboxes. The data is being retrieved from: https://jsonplaceholder.typicode.com/posts. I aim to include checkboxes that, when selected, will filter the list by userId. Here is ...

TypeScript utility function that retrieves properties from an interface based on a specified type

Is there a way to create a new object type that includes only properties from another Object that match specific types, as opposed to property names? For example: interface A { a: string; b: number; c: string[]; d: { [key: string]: never }; } int ...

Vue.js mounted hook failing to trigger

Whenever I try to load my App component, the mounted() lifecycle hook doesn't seem to be triggered: <template> <div> <div v-if='signedIn'> <router-view /> </div> </div> </template&g ...

Is it possible to pass a value back from an Atlassian Forge resolver to a Vue custom UI component?

I have a custom Atlassian Forge resolver and Vue Custom UI setup import Resolver from '@forge/resolver' const resolver = new Resolver() resolver.define('getIssueKey', ({context}) => { const jiraKey = context.extension.issue.key ...

The typed union type FormGroup in Angular stands out for its versatility and robustness

Within my application, users select a value from a dropdown menu to determine which type of FormGroup should be utilized. These formGroups serve as "additional information" based on the selection made. I am currently working with three distinct types of f ...

React-router-dom TypeScript error when defining the type of the prop parameter in the loader

I'm having trouble with the params prop in the loader prop within the routes. I've defined the params in TypeScript, but I'm getting errors that I don't understand. Any help would be appreciated, thanks in advance. I tried to use the Cu ...

Endless cycle in Vue-Router when redirecting routes

I need advice on how to properly redirect non-authenticated users to the login page when using JWT tokens for authentication. My current approach involves using the router.beforeEach() method in my route configuration, but I'm encountering an issue wi ...

Instantiate a fresh object using the new keyword followed by the Class constructor, and if desired,

I'm looking for a class that I can easily create new instances from and optionally assign properties using the constructor. For instance: class Person { name: string; age: number; constructor(props: {name?: string, age?: number}) { this.nam ...

How to deduce a string literal using a ternary conditional in TypeScript

Here is a simple illustration: function doSomething(animal: 'bird' | 'fish'){ } let flies=true; const animal = flies ? 'bird' : 'fish' doSomething(animal); In the assignment to `animal` from the ternary conditio ...

Error Encountered: Unresolved ReferenceError in VUE 3 Component while updating modelValue

I am encountering the error "Uncaught ReferenceError: comp1 is not defined" when emitting "update:modelValue" from the component. Interestingly, this issue only occurs after I have built the project, not during development. Parent: <script setup> i ...