Setting ion-segment value dynamically/reactively

I am wondering if we are suppose to be able to set the value of ion-segment dynamically through a reactive variable. My goal is to be able to pass in a route param or query string to select a specific ion-segment-button on page load or onIonViewDidEnter.

The ion-segment honors my default value and selects the appropriate button, but if I change the value of selectedSegment the selected button doesn’t change (is not reactive).

I am currently on Ionic 5.6.0.

Result
The result is the button staying on Button2 even though selectedSegment is set to button3.

image

Options API

<template>
    <ion-page>
        <ion-header>
            <ion-toolbar mode="md">
                <ion-title>Test selecting segment buttons</ion-title>
            </ion-toolbar>
            <ion-segment :value="selectedSegment" @ionChange="segmentChanged">
                <ion-segment-button value="button1">Button1</ion-segment-button>
                <ion-segment-button value="button2">Button2</ion-segment-button>
                <ion-segment-button value="button3">Button3</ion-segment-button>
            </ion-segment>
        </ion-header>
        <ion-content>
            <div style="text-align: center; margin-top: 15px">
                Button selected: {{ selectedSegment }}
            </div>
        </ion-content>
    </ion-page>
</template>

<script lang="ts">
import {
    IonContent,
    IonHeader,
    IonPage,
    IonTitle,
    IonToolbar,
    IonSegment,
    IonSegmentButton,
} from "@ionic/vue";
import { defineComponent } from "vue";

export default defineComponent({
    name: "Home",
    components: {
        IonContent,
        IonHeader,
        IonPage,
        IonTitle,
        IonToolbar,
        IonSegment,
        IonSegmentButton,
    },
    data() {
        return {
            selectedSegment: "button2",
        };
    },
    methods: {
        segmentChanged(e: CustomEvent) {
            this.selectedSegment = e.detail.value;
        },
    },
    mounted() {
        this.selectedSegment = "button3";
        //this.selectedSegment = this.$route.params.segment.toString();
    },
});
</script>

Composition API

<template>
    <ion-page>
        <ion-header>
            <ion-toolbar mode="md">
                <ion-title>Test selecting segment buttons</ion-title>
            </ion-toolbar>
            <ion-segment
                :value="selectedSegment"
                @ionChange="segmentChanged"
                ref="myIonSegment"
            >
                <ion-segment-button value="button1">Button1</ion-segment-button>
                <ion-segment-button value="button2">Button2</ion-segment-button>
                <ion-segment-button value="button3">Button3</ion-segment-button>
            </ion-segment>
        </ion-header>
        <ion-content>
            <div style="text-align: center; margin-top: 15px">
                Button selected: {{ selectedSegment }}
            </div>
        </ion-content>
    </ion-page>
</template>

<script lang="ts">
import {
    IonContent,
    IonHeader,
    IonPage,
    IonTitle,
    IonToolbar,
    IonSegment,
    IonSegmentButton,
} from "@ionic/vue";
import { defineComponent, onMounted, ref } from "vue";

export default defineComponent({
    name: "Home",
    components: {
        IonContent,
        IonHeader,
        IonPage,
        IonTitle,
        IonToolbar,
        IonSegment,
        IonSegmentButton,
    },
    setup() {
        const myIonSegment = ref();
        const selectedSegment = ref("button2");

        onMounted(() => {
            selectedSegment.value = "button3";
            console.log(myIonSegment.value.$el.value); // Outputs: button2

            myIonSegment.value.$el.value = selectedSegment.value;
            console.log(myIonSegment.value.$el.value); // Outputs: button3
        });

        const segmentChanged = (e: CustomEvent) => {
            selectedSegment.value = e.detail.value;
        };

        return {
            myIonSegment,
            selectedSegment,
            segmentChanged,
        };
    },
});
</script>

I have the very same problem.

Oddly enough, it used to work back with @ionic/vue 5.4.0. I think vue changed some internal propagation methods but had no clue so far.

Thanks @enricodeleo for confirming! I just tried in 5.4.0 and 5.5.0 and it does in fact work. I will create a bug on GitHub. I was waiting to do that to see if it was even suppose to be possible (it seemed like it should work). I’ll link to the issue here once created.

Can you try using v-model instead of :value?

If that still doesn’t work, I can take a look if you provide a GitHub repo.

That totally works! Thank you sooooooo much. I don’t know how many hours I spent on this :slight_smile: I always say the smallest bug/issue/fix always takes the longest time…lol.

1 Like

I think the issue is that when you set :value you are setting it to be the ref object itself, whereas v-model knows how to listen for changes/get the value of the ref.

I can work on some docs for this, since it is confusing at first glance.

1 Like

That would be useful, I’ve been stuck on this for ages, but using v-model worked fine.
I thought I’d already tried that earlier to no avail, but some other code changes must have made it work.
Awesome!

Having this issue as well in Angular 13, had to resort to using ngModel but its also a form so running into the warning in Angular 6+ does not allow ngModel in forms.