Utilizing watcher with computed property in TypeScript VueJS: A comprehensive guide

I'm in the process of creating a unique component that permits the use of any <div> elements as radio buttons. Here is my current code implementation:

<template>
    <div
        class="radio-div"
        :class="selected ? 'selected' : ''"
        @click="handleClick"
    >
        <slot></slot>
    </div>
</template>

<style lang="scss" scoped>
.radio-div {
    display: inline-block;
    border-radius: 5px;
    border: 1px solid #000;
    padding: 5px;
    margin: 5px;
}

.radio-div.selected {
    box-shadow: 0 0 10px rgba(255, 255, 0, 0.5);
    border: 2px solid #000;
}
</style>

<script lang="ts">
import { Vue, Component, Prop, Watch } from "vue-property-decorator";

@Component
export default class RadioDiv extends Vue {
    @Prop()
    val!: string;

    @Prop({
        required: true
    })
    value!: string;

    selected = false;

    mounted() {
        this.selected = this.value === this.val;
    }

    @Watch("value")
    onChange() {
        this.selected = this.value === this.val;
    }

    handleClick(e: MouseEvent) {
        this.$emit("input", this.val);
    }
}
</script>

To utilize this I can place it within a template like so:

<template>
    <div class="q-pa-md">
        <q-card>
            <q-card-section class="bg-secondary">
                <div class="text-h6">Political Affiliation</div>
            </q-card-section>
            <q-separator />
            <q-card-section>
                <radio-div v-model="politicalParty" val="Republican">
                    <div class="text-h6">Republican</div>
                    <p>Wrong answer</p>
                </radio-div>
                <radio-div v-model="politicalParty" val="Democrat">
                    <div class="text-h6">Democrat</div>
                    <p>Wrong answer</p>
                </radio-div>
                <radio-div v-model="politicalParty" val="Independent">
                    <div class="text-h6">Independent</div>
                    <p>These people clearly know what's up</p>
                </radio-div>
            </q-card-section>
        </q-card>
    </div>
</template>

<script lang="ts">
import { Vue, Component, Watch } from "vue-property-decorator";
import RadioDiv from "../components/RadioDiv.vue";

@Component({
    components: { RadioDiv }
})
export default class Profile extends Vue {
    politicalParty = "Independent";;
}
</script>

This all functions correctly. Clicking on the <div> elements switches the selection and updates the variable accordingly.

Now, I aim to integrate this with a global state manager. Instead of using a local politicalParty variable, I have created a computed property like this:

<script lang="ts">
import { Vue, Component, Watch } from "vue-property-decorator";
import RadioDiv from "../components/RadioDiv.vue";
import globalState from "../globalState";

@Component({
    components: { RadioDiv }
})
export default class Profile extends Vue {
    get politicalParty() {
        return globalState.politicalParty;
    }

    set politicalParty(val) {
        globalState.politicalParty = val;
    }
}
</script>

After adding a console.log statement in the setter, I verified that it is being called and updating the variable. However, inserting a console.log statement in my value watcher (within the RadioDiv component) reveals that it is no longer triggered now that computed properties are in use.

How can I reactivate reactivity within my RadioDiv component now that I've transitioned to using global state?

Update

The issue appears not to be specific to custom components or watchers. While awaiting assistance from StackOverflow, I encountered the same problem with Quasar's components:

<template>
...
            <q-card-section>
                <div class="row">
                    <div class="col">
                        <q-slider v-model="age" :min="0" :max="100" />
                    </div>
                    <div class="col">
                        {{ ageText }}
                    </div>
                </div>
            </q-card-section>
...
</template>

<script lang="ts">
...
    get age() {
        return globalState.age;
    }

    set age(val) {
        globalState.age = val;
        this.ageText = "You are " + val + " years old";
    }
...
</script>

This prompted me to experiment by omitting custom components altogether:

<template>
...
    <input type="text" v-model="test" />
    <p>Text: {{ test }}</p>
...
</template>

<script lang="ts">
let testVal = "";
...
    get test() { return testVal; }
    set test(val) { testVal = val; }
...
</script>

Once again, reactivity was absent. When utilizing a computed property with v-model, no changes seemed to occur after the set call.

Answer №1

When considering the reactivity of globalState as just an Object, it becomes evident that it would not exhibit reactive behavior. In this scenario, computed will only access its value once. The same principle applies to testVal, which is simply a non-reactive String.

To imbue reactivity in the computed property test based on testVal, it is necessary to create testVal using Vue.observable():

const testVal = Vue.observable({ x: '' })

@Component
export default class Profile extends Vue {
  get test() { return testVal.x }
  set test(val) { testVal.x = val }
}

A similar approach should be adopted for globalState; exporting a Vue.observable() is essential for ensuring reactivity in your computed properties:

// globalState.js
export default Vue.observable({
  politicalParty: ''
})

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

Is there a way to use regular expressions to search for class names within nested div elements?

I'm struggling to find nested divs like these in my document object model (DOM) <div class="two-columns some-other-class"> <div class="two-columns some-other-class"> </div> </div> I attempted to search for neste ...

Access the value of the observable in TypeScript code

I am currently working with Angularfire2 for handling image uploads and downloads. Unfortunately, I have encountered an issue after the removal of getDownloadURL(). import { finalize } from 'rxjs/operators'; @Component({ selector: 'app-r ...

Guide on showing a message on the server side when pressing a button in the web browser

I need the following question to function seamlessly on all major browsers including Opera, Internet Explorer, Chrome, Safari, and Firefox I am working on an application that requires users to follow a specific order of pages Text1.php, Text2.php, Text3.p ...

How can I create a customized scrollbar for a div element in an Angular 2.0 CLI project?

I am attempting to create a sleek horizontal scroll bar within one of my div elements, similar to the example shown here: https://i.stack.imgur.com/ziWhi.png My project is based on the angular2 CLI. Progress so far: I came across this package angular2-s ...

How can I use jQuery to prevent a click function from running when input fields are left empty

I have step cards with input fields on each card. A "Next" button is provided for each card to change the view. However, I need to prevent the "Next" button from functioning if any input fields on the form are left empty. Below is the code snippet: va ...

Is it possible to implement a custom sign-in form for AWS Cognito?

Is it possible to replace the AWS Cognito hosted UI with a custom form in my Next.js app that utilizes AWS Cognito for authentication? import { Domain } from "@material-ui/icons"; import NextAuth from "next-auth"; import Providers fro ...

Tips for integrating jwt token into axios request

I am facing an issue with my backend endpoint. I can successfully retrieve a list of customers using jwt token on Postman, but when I try to fetch the list from a React app using axios get request, it fails. After reading through this question, I implemen ...

Steps to Design a Button Component in Vue.js

I'm looking to create a custom button component in my Vue Storefront project that links to a third-party site. The link needs to be dynamic, including store.id and product.id parameters. The URL format should be: https://base-url/store.id/product.id ...

Transferring data from JavaScript to PHP using the $.ajax method for storing information in a MySQL database

I am attempting to make a POST call from a JavaScript file to a PHP file in order to insert a variable into a MySQL database. Here are the basic files I am working with: 1° PHP file for sending the call <html> <head> <script ...

V-Treeview enables both activation and opening on click simultaneously

Is there a way to make the item name clickable with two functionalities: Expand it Select it I noticed that this is not possible by default as discussed here: https://github.com/vuetifyjs/vuetify/issues/5947 Does anyone have a workaround for this limitat ...

Accessing PHP variables in JavaScript

Hi there, I am new to all this. I am trying to figure out how to use a PHP variable in JavaScript. Here is a snippet of my code (popup.php): <?php $id_user = $this->session->userdata('id'); ?> <script type="text/javascript"> ...

Creating a two-way binding in VueJS 2 to update contenteditable within a component using a

I am facing an issue with updating an editable element through a component method while also needing to update the element using a JSON import and the parent method. I can successfully update the model, but the editable element is not binding to it. When I ...

How can I convert a Vue template into a JavaScript variable?

I am utilizing Bootbox.js to easily create Bootstrap modal dialogs. The process is straightforward - you simply instantiate the dialog by passing HTML as the 'message' property like so: bootbox.dialog({message: "<div>HTML goes here</div ...

Implementing multiple content changes in a span using javascript

Having an issue with a pause button where the icon should change on click between play and pause icons. Initially, the first click successfully changes the icon from a play arrow to a pause icon, but it only changes once. It seems like the else part of the ...

AngularJs is able to assess an expression in the presence of numerous conditions

Can a function be triggered only when two conditions are met simultaneously? <a id="Send" ng-click="(model.condition1 and model.condition2) || doSomething()"></a> ...

What could be causing my Vuex store state to consistently come up empty in middleware when accessing it through SSR (Server-Side Rendering) with NuxtJS?

Question: I am facing an issue with my middleware files. More specifically, I have a file named authenticated.js. In this file, I have a function that checks for authentication. Here is the code snippet: export default function (context) { //console.l ...

jQuery post method not transmitting POST data successfully

const link = 'http://www.example.com/maketransaction.php?validate=1&key=123'; const amount = 50; const userID = 5; const requestData = {transactionAmount:amount, ID:userID, tag:null}; $(document).ready(function(){ $.ajax({ 'u ...

Update image source dynamically using AJAX and jQuery

Within my app, there exists a web page that contains numerous images with dynamically generated source URLs obtained by sending get requests to the rails server. Initially, these images are assigned a default source. Upon loading the page, another request ...

Why isn't my ajax success data showing up in AngularJS?

Currently, I am working on calling ajax to retrieve my HTML content. However, I am encountering an issue when trying to display that data in a tooltip or popover. Even though I can see the data in the console, the tooltip is showing up as black. I am not s ...

How to specify a single kind of JavaScript object using Typescript

Let's say we have an object structured as follows: const obj = [ { createdAt: "2022-10-25T08:06:29.392Z", updatedAt: "2022-10-25T08:06:29.392Z"}, { createdAt: "2022-10-25T08:06:29.392Z", animal: "cat"} ] We ...