@ionic/vue": "^8.0.0
“vue”: “^3.3.0”,
This is my code for IonSegment. I know about the events @ion-change and @ion-select, the problem is that both trigger only if the value is “new”, so if you click twice on the same button, the second time it doesn’t trigger. So I resulted to having a click function on each button and having a variable that holds the previous model value. First, this is my component:
// I know I can have v-for but just so u see more clearly the values
<ion-segment ref="ionSegmentRef" v-model="calorieSpan">
<ion-segment-button value="lowerThan" @click="segmentClicked">do 350</ion-segment-button>
<ion-segment-button value="fromTo" @click="segmentClicked">350-500</ion-segment-button>
<ion-segment-button value="higherThan" @click="segmentClicked">od 500</ion-segment-button>
</ion-segment>
I am using v-model but I did try with :value=calorieSpan and it doesn’t work either. This is my click function:
segmentClicked() {
if (this.previousValue === this.calorieSpan) {
console.log("making null")
this.calorieSpan = null
// this is just outta desperation, tried with modelValue and value too
this.$refs.ionSegmentRef.$el.modelvalue = null
this.previousValue = null
} else this.previousValue = this.calorieSpan
}
So like this, it does make the value null, however the button doesn’t “un-check” it seemingly stays active. In order to de-select it I would have to dig deep and remove the styles which just overall with all the rest sounds so stupid to do.
Am I doing something wrong? Shouldn’t it just deselect when I null the v-model? It is unchecked when it mounts but once you click on one option there is no way to deselect anymore.
Cant we add something like there is on the radio group? allow-empty-selection? Or am I messing up somewhere? Please help.
Pls heeeelp
Interesting use case! I would argue you are using ion-segment
for an unintended use case. Just my opinion though as another Ionic Vue user It seems they were designed to always have one selected.
What if you just add an additional option “None”?
You’re probably right, I just noticed it actually doesn’t null the value at all? I put {{ calorieSpan }} above my component to check if the value changed and even after the click function that should make it null function runs it remains the same what a shame, I love the styling of this.
As for the other None option, I tried adding a forth display: none
option that I would “click” programatically but the button itself is in a shadow root so I just don’t how to access it, this is as far as I got (it’s included in the making null part of the click function):
this.$refs.ionSegmentRef.$el.lastElementChild.click()
which doesn’t work cause that’s not the button. But the more I try to more I think I will just do it right and style a radio group
I agree, it does look nice!
Having a hidden one is a good idea! Can’t you just set the value
of the ion-segment
to the value of the “none” ion-segment-button
? That is how I programtically set the selected button.
I tried to do this:
<ion-segment ref="ionSegmentRef" :value="calorieSpan">
<ion-segment-button value="lowerThan" @click="segmentClicked">do 350</ion-segment-button>
<ion-segment-button value="fromTo" @click="segmentClicked">350-500</ion-segment-button>
<ion-segment-button value="higherThan" @click="segmentClicked">od 500</ion-segment-button>
<ion-segment-button value="test" class="d-none" @click="segmentClicked">od 500</ion-segment-button>
</ion-segment>
And like this it doesn’t change the calorieSpan variable at all when clicking it does change probably within the segment because the active buttons keep moving as I am clicking but my calorieSpan variable doesn’t react and stays the same
I also tried this this.$refs.ionSegmentRef.$el.value = "test"
and it didn’t change to the button, I tried to also remove the d-none
class (which is display: none
) and it still wouldn’t change it
At this point I feel like the ion-segment has some personal beef with me
For anyone facing the same issue I created this:
<ion-grid class="ion-no-padding">
<ion-row ref="calorieButtonRow" class="ion-btn-row">
<ion-col v-for="(item, key) in calorieSpans" :key="key" cols="4">
<ion-button
:id="key"
selected="false"
:border="key === 'fromTo'"
expand="block"
color="white"
class="mx-0"
@click="optionSelected(key)"
>{{ item.kcal }}
</ion-button>
</ion-col>
</ion-row>
</ion-grid>
<style scoped>
.ion-btn-row {
background-color: rgba(var(--ion-color-caloriespan-rgb));
border-radius: 10px;
padding-left: 2.5px;
padding-right: 2.5px;
}
ion-button {
--background-hover: rgba(var(--ion-color-caloriespan-rgb));
--background-activated: rgba(var(--ion-color-caloriespan-rgb));
margin-top: 2.5px;
margin-bottom: 2.5px;
}
ion-button[selected="false"] {
--color-hover: rgba(var(--ion-color-terShade5-rgb));
}
ion-button[selected="false"]::part(native) {
background-color: rgba(var(--ion-color-caloriespan-rgb));
}
ion-button[selected="true"]::part(native) {
background-color: rgba(var(--ion-color-white-rgb));
}
ion-button[border="true"] {
border-right: 1px solid rgba(var(--ion-color-terShade2-rgb));
border-left: 1px solid rgba(var(--ion-color-terShade2-rgb));
}
</style>
The calorieSpan color is
--ion-color-caloriespan: #eee;
--ion-color-caloriespan-rgb: 238, 238, 238;
This part is to put the border only on the middle element :border="key === 'fromTo'"
And finally this is the function
optionSelected(key) {
const el = document.getElementById(key)
const isAlreadySelected = el.getAttribute("selected") === "true"
if (isAlreadySelected) // code for when the btn is already selected
else {
const previous = this.$refs.calorieButtonRow.$el.querySelector('[selected="true"]')
if (previous) previous.setAttribute("selected", false)
// additional code for selecting the btn
}
el.setAttribute("selected", !isAlreadySelected)
},
Thank you for all your help :))
Well, I just figured it out for you with ion-segment
I think the missing key was not stopping propagation of the click event.
<ion-segment :value="selected">
<ion-segment-button value="all" @click.prevent.stop="handleButtonClick">
<ion-label>All</ion-label>
</ion-segment-button>
<ion-segment-button
value="favorites"
@click.prevent.stop="handleButtonClick"
>
<ion-label>Favorites</ion-label>
</ion-segment-button>
<ion-segment-button
value="no-favorites"
@click.prevent.stop="handleButtonClick"
>
<ion-label>Not My Favorites</ion-label>
</ion-segment-button>
<ion-segment-button value="none" style="display: none">
<ion-label>None</ion-label>
</ion-segment-button>
</ion-segment>
const selected = ref('all');
function handleButtonClick(event: PointerEvent): void {
const newValue = event.target.value;
if (newValue === selected.value) {
selected.value = 'none';
} else {
selected.value = newValue;
}
}
1 Like
Omggg you’re a genius! That’s so much better than mine! Marking this as the solution and implementing asap thank youuu SO MUCH
1 Like