How to dynamically make specific cells editable in a TableSheet?

Posted by: ichioka.yuji on 24 May 2026, 4:20 am EST

    • Post Options:
    • Link

    Posted 24 May 2026, 4:20 am EST - Updated 25 May 2026, 1:54 am EST

    Hi,

    I am trying to make specific cells editable or non-editable in a TableSheet based on a row value (e.g., editable only if type === ‘item’).

    To achieve this, I set locked: true in the default style of the column and applied locked: false inside StyleOptions within conditionalFormats when the formula condition =([@type]=“item”) is met.

    However, the cells remain editable at all times, and the restrictions from StyleOptions.locked do not seem to take effect. It appears that StyleOptions.locked does not affect the actual cell editing state in TableSheet, even when the sheet protection option is enabled.

    ** StyleOptions ** https://developer.mescius.com/spreadjs/api/modules/GC.Data#styleoptions

    Here is my sample code: index-table-sheet.7z

        function initSpread(spread, rows) {
          spread.suspendPaint();
    
          // Add a TableSheet
          const tableSheet = spread.addSheetTab(0, 'Tags', GC.Spread.Sheets.SheetType.tableSheet);
          tableSheet.options.allowAddNew = false;
          tableSheet.rowActionOptions([]);
    
          // Add a DataTable
          const dataManager = spread.dataManager();
          const table = dataManager.addTable('TagsTable', {
            batch: true,
            schema: {
              hierarchy: {
                type: 'Level',
                column: 'level'
              },
              columns: {
                name: { dataName: 'name' },
                address: { dataName: 'address' },
                type: { dataName: 'type' },
                level: { dataName: 'level' },
                rowOrder: { dataType: 'rowOrder' },
              }
            },
            remote: {
              read: async () => window.rows,
            }
          });
    
          // Load data into the DataTable
          table.fetch().then(() => {
    
            // Then, add a new DataView in the DataTable
            const view = table.addView('TagsView', [
              {
                value: 'name',
                caption: 'Name',
                outlineColumn: true,
                width: '*',
                readonly: true,       // Always read-only
              },
              {
                value: 'address',
                caption: 'Address',
                width: '*',
    
                style: {
                  backColor: 'Background 2',
                  locked: true,       // Not editable
                },
    
                // Conditional formatting to make editable if type is 'item'
                conditionalFormats: [{
                  ruleType: 'formulaRule',
                  formula: '=([@type]="item")',
                  style: {
                      borderLeft: { color: 'Accent 2', style: 'medium' },
                      borderTop: { color: 'Accent 2', style: 'medium' },
                      borderRight: { color: 'Accent 2', style: 'medium' },
                      borderBottom: { color: 'Accent 2', style: 'medium' },
                      backColor: 'Accent 2 80',
                      locked: false,  // Editable
                  },
                  priority: 0,
                  stopIfTrue: true,
                }],
              },
              {
                value: 'type',
                caption: 'Type',
                width: 100,
                readonly: true,       // Always read-only
              },
            ]);
    
            // Bind the DataView with the TableSheet
            tableSheet.setDataView(view);
          });

    How can I dynamically enable editing for specific rows based on their data? Any advice would be appreciated.

    Thank you!

  • Posted 24 May 2026, 5:07 am EST

    I have successfully resolved this issue on my own. It turns out that setting readonly: true on the column definition is required to make StyleOptions.locked effective.

            // Then, add a new DataView in the DataTable
            const view = table.addView('TagsView', [
              {
                value: 'name',
                caption: 'Name',
                outlineColumn: true,
                width: '*',
                readonly: true,       // Always read-only
              },
              {
                value: 'address',
                caption: 'Address',
                width: '*',
    
                // Added *********
                // - Makes 'locked' effective by doing this..
                readonly: true,
                // ********* Added 
    
                style: {
                  backColor: 'Background 2',
                  locked: true,       // Not editable
                },
    
                // Conditional formatting to make editable if type is 'item'
                conditionalFormats: [{
                  ruleType: 'formulaRule',
                  formula: '=([@type]="item")',
                  style: {
                      borderLeft: { color: 'Accent 2', style: 'medium' },
                      borderTop: { color: 'Accent 2', style: 'medium' },
                      borderRight: { color: 'Accent 2', style: 'medium' },
                      borderBottom: { color: 'Accent 2', style: 'medium' },
                      backColor: 'Accent 2 80',
                      locked: false,  // Editable
                  },
                  priority: 0,
                  stopIfTrue: true,
                }],
              },
              {
                value: 'type',
                caption: 'Type',
                width: 100,
                readonly: true,       // Always read-only
              },
            ]);

    Is this the proper way to handle it?

  • Posted 25 May 2026, 1:51 am EST

    Hi,

    Yes, your solution is the correct and recommended approach. Here is a brief explanation of why it works:

    WHY locked: false ALONE DID NOT WORK

    In a TableSheet, the column-level readonly property and the style-level locked property operate at two different layers:

    • readonly: true/false on the column definition is the TableSheet’s own editing gate. It controls whether the TableSheet engine allows editing on that column at all.

    • StyleOptions.locked in conditional formats works at the cell style layer, but it only takes effect when the column is first marked as readonly: true — because that tells the TableSheet to defer the edit decision down to the cell-level locked flag.

    Without readonly: true on the column, the TableSheet treats the column as editable by default and never evaluates the locked flag in the conditional format style. This is why locked: false in your conditional format was being ignored.

    THE CORRECT THREE-STEP PATTERN

    Step 1 — Set readonly: true on the column

    → Activates cell-level lock checking for that column

    Step 2 — Set style.locked: true as the default column style

    → Locks all cells in the column by default

    Step 3 — Set locked: false inside the conditionalFormats style

    → Unlocks only the rows that match your condition (e.g. type === ‘item’)

    The key takeaway is:

    readonly: true on the column definition is a prerequisite for StyleOptions.locked

    in conditional formats to have any effect.

    Without it, the TableSheet’s own readonly state takes full control and the cell-level locked flag is never evaluated.

    Your implementation is perfectly aligned with this pattern, so you are all set!

    Best regards,

    Priyam

  • Posted 25 May 2026, 1:56 am EST

    Thank you so much for your prompt confirmation!

Need extra support?

Upgrade your support plan and get personal unlimited phone support with our customer engagement team

Learn More

Forum Channels