[working] alter chips component with a options-group instead of text box



  • I’m going to start writing a chips component that instead of adding chips with a simple text field one would click to bring up a modal options group (check boxes or toggles) that when checked would then appear as chips. One will be able to uncheck them easily by deleting chip or via via the options group.

    Just wondering before I dive into this if someone has done something similar and is willing to share?

    If no one then I’d be happy to take some input on design. My use case is that I have dozens of options of which only a handfull would be chosen but the user. I did just this giant options-group in my current UI but it really is not functional and it’s hard for the user to see quickly which options have been chosen so I figured that chips was was a way to go but still needed the options group in a modal for making choices.



  • Well, my first issue is the chips component has no way to disable the text input field without disabling the click event of the component. Thus there is no way for me to have the click event show a options group. I was hoping not to modify the chips component but just use it but it looks like that may not be possible to access the click event.

    Anyone with any ideas how to bypass this behavior without writing my own version of the chips component??

    Maybe the chips component’s disable property should just hide the text box instead of disabling the entire component or sure keep it but have another prop to hide the text field or if I rewrite this then one could have prop to use either text filed or options group.



  • Ok pretty much working. I can’t remove the text input without disabling the entire chip input component so will just have to leave it for now (made a feature request). Instead I added a :before icon to toggle display of the options group.

    Note: Depends on lodash.find

    component

    <template>
      <div>
       <q-chips-input
       v-model="names"
       v-bind:show="show"
       @input="update()"
       @change="update()"
       float-label='Down Arrow for List of Options'
       :before="[
         {
            icon: 'arrow drop down',
            handler() {
              show = !show
            }
          }
        ]"
        />
       <q-option-group
       v-show="show"
      color="secondary"
      type="checkbox"
      v-model="selected"
      @input="update()"
      @change="update()"
      :options="options"
    />
       </div>
    </template>
    
    <script>
    
    import find from 'lodash.find'
    
    export default {
      data () {
        return {
          show: false,
          selected: []
        }
      },
      props: [ 'value', 'options' ],
      computed: {
        names: {
          get: function () {
            console.log('get', this.selected)
            return this.selected.map(option => {
              return find(this.options, function (o) { return o.value === option }).label
            })
          },
          set: function (updated) {
            console.log('set', this.names, updated, this.selected)
            this.selected.find((sel) => {
              let label = find(this.options, function (o) { return o.value === sel }).label
              console.log('loop', sel, label)
              if (updated.indexOf(label) === -1) {
                this.selected = this.selected.filter(item => item !== sel)
                return true
              }
            })
          }
        }
      },
      methods: {
        update () {
          console.log('updating', this.selected)
          this.$emit('input', this.selected)
        }
      },
      beforeMount () {
        this.selected = this.value
        console.log(this.selected)
      }
    }
    </script>
    
    <style lang="stylus">
    
    @import '~variables'
    
    .on
        background $positive
    
    .off
        background grey
    
    </style>
    

    usage

    <template>
      <div>
      <div>Test chip-option-group</div>
      <chip-option-group v-model="selected" :options="opts" />
      <div> {{ selected }} </div>
      </div>
    </template>
    
    <script>
    
    import ChipOptionGroup from 'src/components/ChipOptionGroup.vue'
    
    export default {
      data () {
        return {
          selected: ['op1', 'op3', 'op6'],
          opts: [
            { label: 'Option 1', value: 'op1' },
            { label: 'Option 2', value: 'op2' },
            { label: 'Option 3', value: 'op3' },
            { label: 'Option 4', value: 'op4' },
            { label: 'Option 5', value: 'op5' },
            { label: 'Option 6', value: 'op6' }
          ]
        }
      },
      components: {
        ChipOptionGroup
      }
    }
    </script>
    
    <style>
    </style>
    


  • 0_1525234419448_a8db1b4c-1fdc-4b71-b1e6-af3d4662bdb8-image.png

    0_1525234348278_42ae047a-402d-48e1-83cd-e962dea3baf4-image.png



  • To disable the text input field without disabling the whole component I ended up doing this to my component.

    in the html tag I put

       @keydown="ignore()"
       ref="chip"
    

    then in methods add an ignore method

      ignore () { this.$refs.chip.blur() },
    

    still would be nice to have disable only disable the text field not the whole component.