vuetifyjs / vuetify

🐉 Vue Component Framework
https://vuetifyjs.com
MIT License
39.89k stars 6.97k forks source link

v-data table is missing @item-selected #16774

Open UglyHobbitFeet opened 1 year ago

UglyHobbitFeet commented 1 year ago

I'm using the v-data-table from v-labs, so I understand this component may not yet be complete. If this property was accidentally omitted, please use this ticket to add it back in.

I am using a v-data-table with the show-select property. When a user checks/unchecks the checkbox I would like to be able to know that the user did that, and the current state of the checkbox.

I have tried using a watcher on the v-model as well as interrogating the @click:row but I cannot seem to get the correct state of the checkbox.

<v-data-table v-model="selected" show-select @click:row="(pointerEvent, item) => doSomething(pointerEvent, item)" />

function doSomething(pointerEvent: PointerEvent, item: any) {
    const el = (pointerEvent?.target as unknown as HTMLTableCellElement);
    const containsCheckbox = el.innerHTML.includes('checkbox'); // User may click in table cell for checkbox, but end up clicking outside the checkbox
    const isCheckbox = el.localName === 'input'; // User clicks the checkbox
    if (isCheckbox || containsCheckbox) {
      const checkboxState = el.value;
      console.log(checkboxState);  // Always is true :(
    }
}

watch(selected.value, (a,b) => {
  console.log(a); // a and b and selected.value always match and show the latest state. I'd expect one to show the prev state
  console.log(b);
  console.log(selected.value)
})

FWIW I'm using the latest version of Vuetify (3.1.6) and Vue (3.2.47)

KaelWD commented 1 year ago

@update:modelValue: https://vuejs.org/guide/components/v-model.html

a and b and selected.value always match and show the latest state

watch(selected, (val, oldVal) => { console.log(val, oldVal) }) shows two separate values for me

The issue list of this repo is exclusively for bug reports and feature requests. For general questions, please join the Discord chat room. You can also check reddit or stackoverflow.

UglyHobbitFeet commented 1 year ago

@KaelWD If this is not planned, then what would the equivalent be for @item-selected? I don't exactly understand your comment other than saying that 'watch' works for you. I'm not sure why mine does not and your does. Regardless, if @item-selected is not planned and no equivalent solution is provided, can this ticket please be changed to feature request? Thanks!

KaelWD commented 1 year ago

@update:modelValue

UglyHobbitFeet commented 1 year ago

@KaelWD @update:modelValue tells me everything that is currently selected, not the actual item that was last checked. Use of that would require custom code for every table written to determine that logic. On a related note @toggle-select-all is no longer a part of data tables and also requires custom code to figure out what rows are currently checkmarked to be considered 'all'.

This seems like a step backwards from what was already implemented in Vuetify

UglyHobbitFeet commented 1 year ago

Here's a use-case of why @toggle-select-all is useful for Vuetify users.

Let's say there is a table with 100 entries and the paging is set to display 5 rows per page. By design when the select-all is selected it will select all rows on the current page (aka 5 of the 100 rows). For my use case I needed all 100 rows to be selected/deselected. So I used @toggle-select-all to capture when a user checked/unchecked 'select all'. I then applied custom logic to ignore the paging and either select all 100 rows or deselect all 100 rows.

If @toggle-select-all is no longer a part of data-tables I would have to write some custom hack to achieve something like that.

UglyHobbitFeet commented 1 year ago

FWIW here is what I'm doing and may provide a valid use-case for @item-selected. It may also explain why I'm getting different results than you for 'watch'

<v-window v-model="someWindow">
  <v-window-item v-for="(customItem, index) in customItems" :key="customItem" :value="index">
    <v-data-table 
       v-model="selected[customItem]"
       @update:modelValue="(a) => updateModelValue(a)"
       :headers="getHeadersForCustomItem(customItem)"
       :items="getItems(customItem)"
       :search="search"
       item-key="id"
       show-select 
       @click:row="(a, b) => rowClicked(a, b)"
       @item-selected="noLongerSupportedInVuetify3($event, customItem)"
       @toggle-select-all="noLongerSupportedInVuetify3($event, customItem)">

const selected: Ref<Record<string, CustomObject[]>> = ref({});

// Watch only triggers if 'selected.value' is used. If I take off .value and only have 'selected' 
// (like you did in your example) it doesn't work
watch(selected.value, (val, oldVal) => { console.log('watch', val, oldVal) });

function updateModelValue(a: any) {
  // Prints out ALL currently selected rows. This doesn't work for me as I only need the users 
  // LAST selection made
  console.log(a);
}

function rowClicked(pointerEvent: PointerEvent, evt: any) {
  // The pointerEvent tells me if the checkbox was clicked on for that particular row (but does 
  // not tell me if it's selected/deselected. If I inspect the dom using Chrome it always shows the 
  // checkbox value as true)

  // The evt contains the row that was selected by the user last.  Great!

  // I need to know the state of the checkbox (whether it was selected or deselected). I have no
  // way of easily inferring this
}
KaelWD commented 1 year ago

This is why we have issue templates.

UglyHobbitFeet commented 1 year ago

Thanks, much appreciated!

nasangw commented 1 year ago

I'm also experienced same issue. I hope that apply reactive feature for v-data-table after rerender selected item.

Always appreciate for Vuetify teams. Thank you : )