Skip to content

[BUG] The merged state of subsequent row cells will be cancelled after using the Worksheet.spliceRows() to delete rows #2881

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
yangguichun opened this issue Jan 21, 2025 · 1 comment

Comments

@yangguichun
Copy link

🐛 Bug Report

After using the

function to delete the specified rows, the merged cells of all subsequent rows will be unmerged.

Lib version: 4.4.0

Steps To Reproduce

For example, there is a worksheet with 2 rows, where A2-O2 of the second row is merged. Now I use worksheet.spliceRows(1,1) to delete the first row. At this time, the original second row moves up to the first row, but the merged state of A1-O1 will be cancelled.

Download the test file in the attachment to the local machine, run the following test code, and then observe the difference between the newly generated xlsx file and the original file, and you can find the problem.

spiceRows-example.xlsx

const rootDir = __dirname;
let workbook = new ExcelJS.Workbook()  
await workbook.xlsx.readFile(path.resolve(rootDir,'./data/spiceRows-example.xlsx'))
let worksheet = workbook.worksheets[0]
worksheet.spliceRows(1,1);
await workbook.xlsx.writeFile(path.resolve(rootDir,'./spiceRows-example-new.xlsx'))

The expected behaviour:

Normally, after the first row is deleted, the merged state of subsequent rows should not change.

Possible solution (optional, but very helpful):

The problem lies in the Worksheet.spliceRows function. The handling of cell merging should be added at line 508 of the Worksheet.js file, similar to the merging handling at line 528. The newly added code is as follows.

spliceRows(start, count, ...inserts) {
    // same problem as row.splice, except worse.
    const nKeep = start + count;
    const nInserts = inserts.length;
    const nExpand = nInserts - count;
    const nEnd = this._rows.length;
    let i;
    let rSrc;
    if (nExpand < 0) {
      // remove rows
      if (start === nEnd) {
        this._rows[nEnd - 1] = undefined;
      }
      for (i = nKeep; i <= nEnd; i++) {
        rSrc = this._rows[i - 1];
        if (rSrc) {
          const rDst = this.getRow(i + nExpand);
          rDst.values = rSrc.values;
          rDst.style = rSrc.style;
          rDst.height = rSrc.height;
          // eslint-disable-next-line no-loop-func
          rSrc.eachCell({includeEmpty: true}, (cell, colNumber) => {
            rDst.getCell(colNumber).style = cell.style;
            // remerge cells accounting for insert offset
            // this is what i added
            if (cell._value.constructor.name === 'MergeValue') {
              const cellToBeMerged = this.getRow(cell._row._number + nExpand).getCell(colNumber);
              const prevMaster = cell._value._master;
              const newMaster = this.getRow(prevMaster._row._number + nExpand).getCell(prevMaster._column._number);
              cellToBeMerged.merge(newMaster);
            }
          });
          this._rows[i - 1] = undefined;
        } else {
          this._rows[i + nExpand - 1] = undefined;
        }
      }
    } else if (nExpand > 0) {
      // insert new cells
      for (i = nEnd; i >= nKeep; i--) {
        rSrc = this._rows[i - 1];
        if (rSrc) {
          const rDst = this.getRow(i + nExpand);
          rDst.values = rSrc.values;
          rDst.style = rSrc.style;
          rDst.height = rSrc.height;
          // eslint-disable-next-line no-loop-func
          rSrc.eachCell({includeEmpty: true}, (cell, colNumber) => {
            rDst.getCell(colNumber).style = cell.style;

            // remerge cells accounting for insert offset
            if (cell._value.constructor.name === 'MergeValue') {
              const cellToBeMerged = this.getRow(cell._row._number + nInserts).getCell(colNumber);
              const prevMaster = cell._value._master;
              const newMaster = this.getRow(prevMaster._row._number + nInserts).getCell(prevMaster._column._number);
              cellToBeMerged.merge(newMaster);
            }
          });
        } else {
          this._rows[i + nExpand - 1] = undefined;
        }
      }
    }

    // now copy over the new values
    for (i = 0; i < nInserts; i++) {
      const rDst = this.getRow(start + i);
      rDst.style = {};
      rDst.values = inserts[i];
    }

    // account for defined names
    this.workbook.definedNames.spliceRows(this.name, start, count, nInserts);
  }
@zjqiangwudi
Copy link

There are also the same problems on insertRows and duplicateRow.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants