9

I am using vue for data binding. I want to create a widget for access level control so I need allow, deny, and indeterminate states.

This markup is good but there is no indeterminate state:

<div class="row" v-for='a in context.This.Actions'>
    <div class="col-96">
        <input class="custom-control-input access-checkbox" v-bind:id="'chk_'+a.Name" v-bind:value="a.Id" v-model="context.This.RoleActions" indeterminate="true" type="checkbox" />
        <label class="pointer" v-bind:for="'chk_'+a.Name">{{ a.Name }}</label>
    </div>
</div>

The variables are :

context.This.Actions = [
    { "Id": "id_1",
      "Name": "AAA"
    },
    { "Id": "id_2",
      "Name": "BBB"
    },
    { "Id": "id_3",
      "Name": "CCC"
    }
]

context.This.RoleActions = [ "id_1", "id_2" ]

I want this change:

context.This.RoleActions = [ {"id_1":true}, {"id_2":false} ]

and I expect the below result:

  • The first checkbox: checked

  • The second checkbox: unchecked

  • The other one: indeterminate

3 Answers 3

21

Indeterminate is a DOM property on a checkbox, which means putting it in the markup won't have an effect, it needs to be applied programmatically.

Even after doing that, keep in mind the state of a checkbox is still either checked or not checked. This is important to keep in mind when processing the form. The difference is visual only. (source)

With those caveats in mind, in Vue 2 you can add an indeterminate property to a checkbox like so:

<input type="checkbox" indeterminate.prop="true">

or bind to a dynamic value in your component:

<input type="checkbox" :indeterminate.prop="dataProperty">

I would recommend refactoring with this in mind.

Sign up to request clarification or add additional context in comments.

1 Comment

1

I had a similar issue using props with checkbox to support 2 and 3 states . to handle this I used computed property with getter and setter using Vuetify checkbox

Here is my example

<template>
  <v-container class="checkbox-container">
    <v-checkbox
      type="checkbox"
      :indeterminate="indeterminate"
      :color="indeterminate ? '#767575' : 'success'"
      v-model="internalState"
      @click.stop="onCheckbox"
      @keyup.space.prevent="onCheckbox"
    ></v-checkbox>
  </v-container>
</template>

<script>
/**
 * Responsability: boolean field editor checkbox
 * When @threeState is true : following states (check, uncheck, indeterminate) otherwise (check, uncheck)
 * @checkboxState is an external state where it contains always the current state of checkbox
 **/
export default {
  model: {
    // v-model prop
    prop: 'checkboxState',
  },
  props: {
    threeState: Boolean,
    /**
     * Init state is the starting state Which the chekbox starts from.
     * by defining initstate it will ignore the default input @boolProperty
     **/
    initState: {
      type: String,
      default: 'false',
    },
    // Reperesent the value of checked state in model
    config: {
      type: Object,
      default: () => ({
        checked: 'true',
        unchecked: 'false',
        indeterminate: null,
      }),
    },
    checkboxState: {
      type: String,
    },
  },

  data() {
    return {
      internalState: this.checkboxState,
      indeterminate: false,
    }
  },

  computed: {
    state: {
      get() {
        return this.checkboxState
      },
      set(newState) {
        this.changeCheckboxState(newState)
      },
    },
  },

  // Change the state of checkbox after DOM is mounted
  mounted() {
    this.changeCheckboxState(this.initState)
  },

  methods: {
    changeCheckboxState(state) {
      this.$vnode.data.model.callback(state)
      this.internalState = state === this.config.checked
      this.indeterminate = state === this.config.indeterminate
    },

    onCheckbox() {
      if (this.threeState) {
        switch (this.state) {
          case this.config.unchecked:
            this.state = this.config.checked
            break
          case this.config.checked:
            this.state = this.config.indeterminate
            break
          case this.config.indeterminate:
            this.state = this.config.unchecked
            break
        }
      } else {
        this.state = (!(this.state === this.config.checked)).toString()
      }
    },
  },
}
</script>

<style lang="scss" scoped>
.checkbox-container {
  width: 50px;
}
</style>

Comments

0

Simple example

<template>
  <input
    type="checkbox"
    :indeterminate="isIndeterminate"
    :checked="isChecked"
    :value="modelValue"
    @input="$emit('update:modelValue', isChecked)"
    @click="toggleCheckState"
  />
</template>

<script setup lang="ts">
const props = defineProps({
  modelValue: { type: Boolean, default: undefined }
})
defineEmits(['update:modelValue'])
import { onMounted, ref } from 'vue'

const isChecked = ref<boolean | undefined>(false)
const isIndeterminate = ref(false)

onMounted(() => {
  if (props.modelValue == undefined) isIndeterminate.value = true
  else isChecked.value = props.modelValue
})

function toggleCheckState() {
  if (isIndeterminate.value) {
    isChecked.value = true
    isIndeterminate.value = false
  } else if (isChecked.value == false) {
    isChecked.value = undefined
    isIndeterminate.value = true
  } else {
    isChecked.value = false
    isIndeterminate.value = false
  }
}
</script>

Usage

<SmartCheckbox v-model="anyRef" /> 

{{ anyRef}}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.