Unable to capture changes such as adding new rows to a worksheet with using observeDeep method

Hello helpers,

I’m working to create a tiny spreadsheet using Yjs and encounting a issue with observeDeep(). I wanted to observe any changes of worksheet, rows or values in a workbook (a Y.Map as a collection of worksheets) by using observeDeep() method, but it didn’t work. I couldn’t capture any changes like adding new rows into a worksheet (a Y.Array<Y.Array<any>> object), or adding new values into a row (a Y.Array<any> object). Plase give me any help.

Do you think if this issue might be somewhat related to [Initial offline value of a shared document - #13 by dmonad]…

  private test() {
    const sync = (doc1: Y.Doc, doc2: Y.Doc) => {
      const state1 = Y.encodeStateAsUpdate(doc1);
      const state2 = Y.encodeStateAsUpdate(doc2);
      Y.applyUpdate(doc1, state2, doc2);
      Y.applyUpdate(doc2, state1, doc1);
    }

    const init = (doc: Y.Doc, sheetName: string) => {
      // Set up a new worksheet in a 'sheets' map collection.
      const sheets = doc.getMap('sheets') as Y.Map<Y.Array<Y.Array<any> | null>>;
      sheets.set(sheetName, new Y.Array<Y.Array<any> | null>());

      // Observe any changes of worksheets, rows, or cells in the 'sheets' collection.
      sheets.observeDeep((events: Y.YEvent<any>[], tr: Y.Transaction) => {
        if (tr.origin === doc) return;
        for (const event of events) {
          console.log('event path:', event.path.toString());
        }
      });
    }

    const sheetName = 'Sheet1';

    // Prepare two spreadsheet-like documents
    const doc1 = new Y.Doc();
    const doc2 = new Y.Doc();
    init(doc1, sheetName);
    init(doc2, sheetName);

    // Add a value at cell (2, 1) of the worksheet in doc1
    const sheets = doc1.getMap('sheets') as Y.Map<Y.Array<Y.Array<any> | null>>;
    const sheet = sheets.get(sheetName)!;
    doc1.transact(() => {
      // insert a new Y.Array at the position of row 2
      const rows = [null, null, new Y.Array<any>()];
      sheet.insert(0, rows);

      // insert a new cell value at the position of columnn 1
      sheet.get(2)!.insert(0, [null, 'Hello']);
    }, doc1);

    // Sync doc1 and doc2
    sync(doc1, doc2); // Just 'event path: ' was logged twice. No events of adding new rows or new values in a sheet were captured.

    // See if doc2 has the same value at cell (2, 1) of the worksheet.
    const sheets2 = doc2.getMap('sheets') as Y.Map<Y.Array<Y.Array<any> | null>>;
    const value = sheets2.get(sheetName)?.get(2)?.get(1);
    console.log('value of cell(2, 1):', value);   // 'value of cell(2, 1): Hello' <-- OK
  }

Hi, welcome.

I haven’t used observeDeep a lot, but it looks like it has something to do with how changes are collated when multiple modifications are made before a sync. i.e. You only get one event when all the changes sync, not separate events for each change.

When I do an additional sync after the docs are initialized, then the next sync does indeed report the added cells in the observeDeep event.

Demo: View in CodeSandbox

I’m not sure, but maybe you can figure out the individual row/cell changes through some combination of e.path, e.keysChanged, and e.changes.

When I do an additional sync after the docs are initialized, then the next sync does indeed report the added cells in the observeDeep event.

Thank you raine,

The demo you made is helpful for me to understand what data each event has. Even though seeing the log below, I’m still unsure how I observe from event data a value in which cell (row / column index) of what sheet (sheet name) was added. I have been wondering if event.path provides such infomation, but there is no information on row / column index where a cell was changed in the below log… :thinking:

insert row in doc1
insert cell in doc1
sync
event {
clientID: 3105377607,
origin: 1612096931,
keysChanged: undefined,
changes: {
added: Set(2) { [Item], [Item] },
deleted: Set(0) {},
delta: [ [Object] ],
keys: Map(0) {}
},
path: [ ‘Sheet1’ ]
}