Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Toggle-Group to set Toggle Radio exclusively #38

Open
vonnnassau opened this issue Apr 16, 2021 · 3 comments
Open

Toggle-Group to set Toggle Radio exclusively #38

vonnnassau opened this issue Apr 16, 2021 · 3 comments
Assignees

Comments

@vonnnassau
Copy link

A radiobutton is usually used in a group to make an exclusive option, the same way as buttons in <Button-Group exclusive> would behave. But there is no <Toggle-Group> for this.

As a workaround I wanted to set the states by script, but it seems a <toggle> always visually changes between true/false when being clicked on. I was expecting this toggle to visually stay false (radiobox-blank) while repeatedly clicking, but it keeps on switching between radiobox-blank and radiobox-marked while the value toggleState stays false.

<Toggle radio @click="toggleFalse" :state=toggleState @update="val => toggleState = false" />
  
<anno>{{toggleState}} </anno>

data: () => ({
	toggleState: false,
	}),

methods: {
	toggleFalse() {
	this.toggleState = false;
    }

Is there another workaround or would a <Toggle-Group> be useful because radiobuttons always perform with more than one in a group anyway? Many thanks!

@Inventsable
Copy link
Member

Inventsable commented Apr 17, 2021

Hey Erik, do you mean like this?

<Toggle> does accept v-model so assignment can be done relatively easily and has a readOnly boolean prop so that user interaction isn't considered. You can toggle the siblings either through a watcher or via the @update callback, but in the case of this screen recording, the entirety of the code is this (which is an App.vue file, though should be easy to abstract the logic from):

<template>
  <div id="app">
    <Menus refresh debug />
    <Panel>
      <Toggle
        radio
        v-model="stateA"
        label="Some option"
        @update="updateState($event, 'A')"
        :readOnly="stateA"
      />
      <Toggle
        radio
        v-model="stateB"
        label="Some option"
        @update="updateState($event, 'B')"
        :readOnly="stateB"
      />
      <Toggle
        radio
        v-model="stateC"
        label="Some option"
        @update="updateState($event, 'C')"
        :readOnly="stateC"
      />
    </Panel>
  </div>
</template>

<script>
export default {
  data: () => ({
    stateA: true,
    stateB: false,
    stateC: false,
  }),
  computed: {
    /**
     * If you find yourself needing an Array like [true, false, false], you could
     * use a watcher on this array and trigger some handler function so the data
     * is Array-based like Button-Group instead of singular like in this example
     */
    selection() {
      return ["A", "B", "C"]
        .map((id) => this[`state${id}`])
        .filter((val) => val);
    },
  },
  methods: {
    updateState(state, ID) {
      // First gather up all our targets
      const groupList = ["A", "B", "C"];
      // Filter out the id currently being toggled
      let siblings = groupList.filter((id) => id !== ID);

      // If this id has been toggled true, then set all siblings to false
      if (state)
        siblings.forEach((sibling) => {
          this[`state${sibling}`] = false;
        });
      else {
        /**
         * This should never trigger because Toggles are set to readOnly when true.
         * The reasoning behind this is to prevent a user from toggling the only true
         * radio button back to false, leaving us without any option selected.
         */
      }
    },
  },
};
</script>

Computed in the above isn't needed, just an example of an alternate way to collect the data in line with <Button-Group exclusive />.

While it's relatively easy to write out some manual mock of this, I'm not sure that it would be as simple to create a dynamic parent component like Toggle-Group. Or at least, I don't know until I try it, but generally it can be difficult to work with wrapper components having stateful children -- Button-Group isn't ideal because it has to comb through it's children's CSS classes to determine their states. I'll think about this more and we might be able to brainstorm a better solution together, but in the meantime let me know if this isn't what you meant.

@Inventsable
Copy link
Member

Apparently the brutalism documentation doesn't include readOnly and v-model, apologies. In any case when there are requests or concerns with certain components like Toggle, feel free to peek at the code for that component because in many instances I'd added extra functions and props to them that I wasn't sure any one else would want to use or know about. I'll try to update the docs soon, but Github actions recently broke for me so it's no longer as simple as pushing a new commit.

@Inventsable Inventsable self-assigned this Apr 17, 2021
@vonnnassau
Copy link
Author

Hi Tom, thank you for this great example, this is the functionality I was looking for, very clear. No need for apologies at all, I now see it was all there. I'm peeking around vigorously, but there is a lot plus Vue is still new to me, so I got a little lost there.

As a solution I also tried a <button> in <button-group exclusive> and switch icon between radiobox-blank and radiobox-marked. Downside there was the backgroundcolor of the button get brighter on mouse-over, which a <toggle radio> does not. If a button has the option to not light up, then the radiobutton might be part of button instead of toggle. Lost the example, but can make it again if useful. For now I'm happy, many thanks for the help and all this brutalism.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants