VisActor / VisActor/VTable

[Bug] 在Vue中,使用多级数据源,并通过数组的方式定义 field 时,Cell 的修改无法同步到数据上

Open
#4,169 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug
Dominant language
TypeScript
Stars
3.7k
Forks
486
Avg merge
1d 19h
Merged PRs (30d)
16

Description

Version

1.19.2

Link to Minimal Reproduction

https://www.visactor.io/vtable/demo-vue/edit-data/edit-cell

Steps to Reproduce

复制以下修改后的代码到官方的示例中进行全选替换,修改的要点在于给 birthday: {data: generateRandomBirthday()} 这里给数据源中的birthday添加了一个data层级,然后在定义field时候使用field: ['birthday', 'data']方式指定层级,如此设置后,表格数据读取正常,但是使用birthday的日期编辑器编辑,会发现日期无法更改,似乎响应性丢失。

const input_editor = new VTable_editors.InputEditor();
const date_input_editor = new VTable_editors.DateInputEditor();
VueVTable.register.editor('input-editor', input_editor);
VueVTable.register.editor('date-input-editor', date_input_editor);

function generateRandomString(length) {
  let result = '';
  const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
  for (let i = 0; i < length; i++) {
    result += characters.charAt(Math.floor(Math.random() * characters.length));
  }
  return result;
}

function generateRandomHobbies() {
  const hobbies = [
    'Reading books',
    'Playing video games',
    'Watching movies',
    'Cooking',
    'Hiking',
    'Traveling',
    'Photography',
    'Playing musical instruments',
    'Gardening',
    'Painting',
    'Writing',
    'Swimming'
  ];

  const numHobbies = Math.floor(Math.random() * 3) + 1;
  const selectedHobbies = [];

  for (let i = 0; i < numHobbies; i++) {
    const randomIndex = Math.floor(Math.random() * hobbies.length);
    selectedHobbies.push(hobbies[randomIndex]);
    hobbies.splice(randomIndex, 1);
  }

  return selectedHobbies.join(', ');
}

function generateRandomBirthday() {
  const start = new Date('1970-01-01');
  const end = new Date('2000-12-31');
  const randomDate = new Date(start.getTime() + Math.random() * (end.getTime() - start.getTime()));
  const year = randomDate.getFullYear();
  const month = randomDate.getMonth() + 1;
  const day = randomDate.getDate();
  return `${year}-${month < 10 ? '0' + month : month}-${day < 10 ? '0' + day : day}`;
}

function generateRandomPhoneNumber() {
  const areaCode = ['130', '131', '132', '133', '134', '135', '136', '137', '138', '139'];
  const prefix = areaCode[Math.floor(Math.random() * areaCode.length)];
  const suffix = String(Math.random()).substr(2, 8);
  return prefix + suffix;
}

const generatePersons = count => {
  return Array.from(new Array(count)).map((_, i) => {
    const first = generateRandomString(10);
    const last = generateRandomString(4);
    return {
      id: i + 1,
      email1: `${first}_${last}@xxx.com`,
      name: first,
      lastName: last,
      hobbies: generateRandomHobbies(),
      birthday: {data: generateRandomBirthday()},
      tel: generateRandomPhoneNumber(),
      address: `No.${i + 100} ${generateRandomString(10)} ${generateRandomString(5)}`,
      sex: i % 2 === 0 ? 'boy' : 'girl',
      work: i % 2 === 0 ? 'back-end engineer' : 'front-end engineer',
      city: 'beijing'
    };
  });
};

const records = generatePersons(10);
const columns = [
  { field: 'id', title: 'ID', width: 80, sort: true },
  {
    field: 'full name',
    title: 'Full name',
    columns: [
      { field: 'name', title: 'First Name\n(input editor)', width: 120, editor: 'input-editor' },
      { field: 'lastName', title: 'Last Name\n(input editor)', width: 100, editor: 'input-editor' }
    ]
  },
  { field: ['birthday', 'data'], title: 'birthday\n(date editor)', width: 120, editor: 'date-input-editor' },
  { field: 'sex', title: 'sex\n(list editor)', width: 100, editor: 'list-editor' },
  { field: 'address', title: 'address\n(textArea editor)', width: 300, editor: 'textArea-editor' },
  { field: 'tel', title: 'telephone', width: 150 },
  { field: 'work', title: 'job', width: 200 },
  { field: 'city', title: 'city', width: 150 }
];

const option = {
  enableLineBreak: true,
  autoWrapText: true,
  limitMaxAutoWidth: 600,
  heightMode: 'autoHeight',
  editCellTrigger: 'click',
  keyboardOptions: {
    copySelected: true,
    pasteValueToCell: true,
    selectAllOnCtrlA: true
  }
};

const app = createApp({
  template: `
    <vue-list-table :options="option" :records="records">
      <ListColumn
        v-for="column in columns"
        :key="column.field"
        :field="column.field"
        :title="column.title"
        :width="column.width"
        :columns="column.columns"
        :editor="column.editor"
      />
    </vue-list-table>
  `,
  data() {
    return {
      records,
      columns,
      option
    };
  }
});

app.component('vue-list-table', VueVTable.ListTable);
app.component('ListColumn', VueVTable.ListColumn);

app.mount(`#${CONTAINER_ID}`);

// release Vue instance, do not copy
window.customRelease = () => {
  app.unmount();
};
Current Behavior

指定多层级的数据源后,修改无法同步到数据源

Expected Behavior

指定多层级的数据源后,修改可以同步到数据源

Environment
- OS: Windows 11
- Browser: Chrome 138
- Framework: Vue 3.5
Any additional comments?

No response

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the linked Vue minimal reproduction and the VueVTable.ListTable/ListColumn integration, focusing on the date-input editor for the nested field ['birthday', 'data']. Trace how an edit is written back to records and verify the nested birthday data updates reactively. Done means editing the birthday cell synchronizes the change to the data source.

Written by the indexing model from the issue text.

Assessment

Tech stack
javascript, typescript
Domain
frontend
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
42/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.