1

I have this html:

<div
class="data__file"
v-for="(data, index) in paginatedData"
:key="index"
>
 <label class="data__info" :for="data.idfile" @click="onClickWithShift($event, index)">
   <img
     :src="data.link"
     alt=""
     :class= "{ 'data__image' : 1 ,'data__image-active' : (data.checked === 1) }"
    />
    <input
     v-if="isManager === true"
     type="checkbox"
     class="data__access"
     :value="data.idaccess"
     :checked="(data.checked === 1) ? 1 : null"
     v-model="checkedFilesPermission"      
    />
          
    <input
     v-if="isManager === false"
     type="checkbox"
     class="data__access"
     :value="data.idfile"
     :checked="(data.checked === 1) ? 1 : null"
     v-model="checkedFilesDownload"       
    />
    </label>
</div>

This code generate list of checkbox inputs, then I need when user click on label with shift (because input`s is display:none), all checkboxes between clicked inputs will checked or unchecked like it make with jquery here How can I shift-select multiple checkboxes like GMail?

But I cant realise how I can get it.

Big thanks to user Spiky Chathu, I did how He said, and its work without v-model , but when I try use v-model, it doesn`t work.

also this is my data:

data() {
    return {
      isManager: this.$store.getters.isManager,
      checkedFilesPermission: [],
      checkedFilesDownload: [],
      lastCheckedIdx: -1,
      checkedCount: 0,  
      paginatedData: [
        {"link":"images/2020/08/20200803.jpg","idfile":296,"idaccess":2},
        {"link":"images/2020/08/20200807.jpg","idfile":6,"idaccess":99},
        {"link":"images/2020/08/20200812.jpg","idfile":26,"idaccess":29},
        {"link":"images/2020/08/202123.jpg","idfile":960,"idaccess":2919},
        {"link":"images/2020/08/2020032.jpg","idfile":16,"idaccess":9339},
        {"link":"images/2020/08/20200000.jpg","idfile":2,"idaccess":9},
      ]
    };

I think main problem that VUE somehow block input with v-model

Big D
  • 45
  • 8

2 Answers2

1

I have come up with a solution to your problem. I have added a mock object to recreate the same scenario hoping that you have a array of objects.


Editted : Solution has been modified to cater multiple deselect scenario


new Vue({
  el: '#app',
  data: {
    paginatedData: [
      {"link":"https://img.icons8.com/list","idfile":296,"idaccess":2},
      {"link":"https://img.icons8.com/list","idfile":6,"idaccess":99},
      {"link":"https://img.icons8.com/list","idfile":26,"idaccess":29},
      {"link":"https://img.icons8.com/list","idfile":960,"idaccess":2919},
      {"link":"https://img.icons8.com/list","idfile":16,"idaccess":9339},
      {"link":"https://img.icons8.com/list","idfile":2,"idaccess":9},
    ],
    lastCheckedIdx: -1,
    checkedFilesPermission : []
  },
  methods: {
    onClickWithShift(event, idx, idFile) {
  
      var action = (this.checkedFilesPermission.indexOf(idFile) === -1) ? 'select' : 'deselect';
      
      if (event.shiftKey && this.lastCheckedIdx !== -1) {
      
        var start = this.lastCheckedIdx;
        var end = idx-1;
        // can select top to bottom or bottom to top
        // always start with lesser value
        if (start > end) {
          start = idx+1;
          end = this.lastCheckedIdx;
        }
        
        for (var c = start; c <= end; c++) {
          var currentIdFile = this.paginatedData[c]['idfile'];
          this.markSelectDeselect(c, action, currentIdFile);
        }
      }
      
      this.markSelectDeselect(idx, action, idFile);
      this.lastCheckedIdx = idx;
      
      if (this.checkedFilesPermission.length === 0) {
        //reset last checked if nothing selected
        this.lastCheckedIdx = -1;
      }
    },

    markSelectDeselect(idx, action, idFile) {
      
      var currentPos = this.checkedFilesPermission.indexOf(idFile);
      
      if (action === 'select' && currentPos === -1) {
        this.checkedFilesPermission.push(idFile);
      } else if (action === 'deselect' && currentPos !== -1){
        this.checkedFilesPermission.splice(currentPos, 1);
      }
    }
  }
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.js"></script>
<div id="app">
  <div
      class="data__file"
      v-for="(data, index) in paginatedData"
      :key="index"
  >
      <input
          :id="data.idfile"
          type="checkbox"
          class="data__access"
          :value="data.idfile"
          v-model="checkedFilesPermission"
      />
       <label class="data__info" :for="data.idfile" @click="onClickWithShift($event, index, data.idfile)">
          <img
              :src="data.link"
              alt=""
              :class= "{ 'data__image' : 1 ,'data__image-active' : (checkedFilesPermission.indexOf(data.idfile) !== -1) }"
          />
      </label>
  </div>
</div>

You need to click on the image icon to see the result, since you have mentioned the input is hidden. I kept it visible here so that you can see it is actually getting changed

Chathuranga K
  • 216
  • 1
  • 5
  • thanks for your time and work, but in my page everything is work, but checkbox between first and last inputs it steel doesnt checked, and I think this is because I use on every input v-model="checkedFilesPermission" I use it to know what inputs is checked and then I get this array and put it in axios request So my code is looks like that But I think problem not in that – Big D Sep 25 '20 at 08:34
  • Can problem be in `data.idFile` ? Because it not like `[1,2,3,4,5]` it`s like `[4,1,10,21,8,5]` ? – Big D Sep 25 '20 at 08:53
  • can you update your question with "paginatedData" data object and checkedFilesPermission to figure out what could be the problem – Chathuranga K Sep 25 '20 at 10:23
  • I make changes in example, and please, can you show how implemented multiple deselect – Big D Sep 25 '20 at 11:45
  • @BigD Sure I can change the code to achieve multiple deselect. Can you also put the code of "checkedFilesPermission" which you use for v-model. I need to have a look at it to figure out the selection issue – Chathuranga K Sep 25 '20 at 12:06
  • For "checkedFilesPermission" it has no code, this is just v-model on input, when user checked checkbox or uncheck it, Vue put value of input in array "checkedFilesPermission" . This is just a empty array at start, and then when user click to label (or input) vue put inside this array value of input, and then I use this array to send request with axios, so "checkedFilesPermission" is just a simple variable – Big D Sep 25 '20 at 12:34
  • I have implemented the multiple deselect scenario as well and simplified the code. I have used same implementation like you mentioned with "checkedFilesPermission". Let me know if this solves everything – Chathuranga K Sep 25 '20 at 14:42
  • OMG it`s work, and you a genius =) Thank you so much! – Big D Sep 28 '20 at 08:13
1

Here's something I just tried that seems to do the work

<template>
  <div>
    <div v-for="(item, index) in items" :key="index">
      <label>
        <input type="checkbox" v-model="item.checked" @click="checked($event, index)">
        {{item.file}}
      </label>
    </div>
    <pre>{{items}}</pre>

  </div>
</template>

<script>

export default {
  data() {
    return {
      lastCheckedIndex: null,
      lastChange: null,
      items: [
        { file: "foo1", idx: 10 },
        { file: "foo2", idx: 20 },
        { file: "foo3", idx: 40 },
        { file: "foo4", idx: 30 },
        { file: "foo5", idx: 10 },
        { file: "foo6", idx: 90 },
        { file: "foo8", idx: 50 },
      ]
    }
  },
  methods: {
    checked(event, index) {
      // wheter or not to the multiple selection
      if (event.shiftKey && (null != this.lastCheckedIndex) && (this.lastCheckedIndex != index)) {

        const dir = index > this.lastCheckedIndex ? 1 : -1; // going up or down ?
        const check = this.lastChange;                      // are we checking all or unchecking all ?

        for (let i = this.lastCheckedIndex; i != index; i += dir) {
          this.items[i].checked = check;
        }
      }

      // save action
      this.lastCheckedIndex = index; 
      this.lastChange = !this.items[index].checked; // onclick is triggered before the default change hence the !
    }
  },
};

</script>
Sélim Achour
  • 718
  • 4
  • 7