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.