# CodeMirror 6: Proper way to listen for changes

**URL:** <https://discuss.codemirror.net/t/codemirror-6-proper-way-to-listen-for-changes/2395>\
**Category:** Uncategorized\
**Created:** [April 27, 2020, 8:12pm UTC](https://discuss.codemirror.net/t/codemirror-6-proper-way-to-listen-for-changes/2395 "2020-04-27T20:12:12Z")\
**Posts on this page:** 1\
**Showing post:** 9

<div class="post-metadata">

**Author:** ![raldone01](https://discuss.codemirror.net/user_avatar/discuss.codemirror.net/raldone01/32/834_2.png) [@raldone01](https://discuss.codemirror.net/u/raldone01)\
**Post date:** [August 24, 2020, 3:05pm UTC](https://discuss.codemirror.net/t/codemirror-6-proper-way-to-listen-for-changes/2395/9 "2020-08-24T15:05:38Z")

</div>

Ok thank you for clarifying. I understand how to listen for changes. I still don’t understand the codemirror modular system. A graphic like this [one](https://vuejs.org/images/lifecycle.png) would help a lot.

I modifed the [split view example](https://codemirror.net/6/examples/split/). I can now keep an arbitrary amount of editors in sync. They can be opened and closed in any order. Awesome. Thank you for that example. It helped me understand that the editor states diverge and are immutable.

I would like to create completely different UIs for various file types.  
.bin -\> Hex editor  
.json -\> Json editor  
.custom -\> Custom editor  
It should be possible to have a codemirror and a hex editor of the same file open at the same time.

I currently have the following:

```auto
  /**
   * https://codemirror.net/6/examples/split/
   */
  private syncDispatch(fromEditorViewRef: { editorView?: EditorView }) {
    return (tr: Transaction): void => {
      // this should never happen as the editorref is populated directly after the constructor
      if (!fromEditorViewRef.editorView) {
        console.log(tr)
        throw Error('Trans but editor undefined.')
      }

      // the EditorView that caused the transaction
      const fromEditorView = fromEditorViewRef.editorView
      fromEditorView.update([tr])

      if (!tr.changes.empty && !tr.annotation(syncAnnotation)) {
        // share the transactions with all other editorViews
        for (const editorView of this.editorViews)
          if (editorView !== fromEditorView) {
            editorView.dispatch({
              changes: tr.changes,
              annotations: syncAnnotation.of(true)
            })
          }

        // I could deliver the changes to my other editors from here but that feels hacky and they would have to register and unregister their listeners

        // debounce file changes to avoid saving everytime a key is pressed
        if (this.saveTimeout)
          clearTimeout(this.saveTimeout)
        this.saveTimeout = setTimeout(() => { this.save(fromEditorView) }, this.saveDelay)
      }
    }
  }

  /**
   * All other editors should also call this function and modify the file through that editor instance.
   */
  async createEditor(): Promise<EditorView> {
    let editorState: EditorState
    if (this.editorViews.length)
      // a editor has already been created get use its state as a base
      editorState = this.editorViews[0].state
    else
      // this is the first editor create a new state with the default extensions for a text editor
      editorState = await this.initialEditorState()

    // As dispatch functions can only be provided to the constructor and the editorView doesn't exist yet a reference object has to be used.
    const editorViewRef: {
      editorView?: EditorView
    } = {}
    const newEditorView = new EditorView({
      state: editorState,
      // create a dispatch function which knowns what editorView is responsible for the transactions.
      dispatch: this.syncDispatch(editorViewRef)
    })
    // set the created editorView so that the dispatch function knowns where the transactions come from.
    editorViewRef.editorView = newEditorView

    // add the editorView to the list of editorViews to keep in sync by the dispatch function
    this.editorViews.push(newEditorView)
    return newEditorView
  }

```

The normal TextEditor calls the `createEditor` function and attaches it to the dom.  
The HexEditor calls the `createEditor` function gets a EditorView and can update the other TextEditor instances through the `dispatch` function. It could listen to changes via the `syncDispatch` function. That however seems like I am doing it wrong because the EditorView would have a nonattached `.dom` and update it right? I also can’t use `EditorView.updateListener.of(update => ...)` because the base EditorState is already created and extensions can’t be added anymore.

How would you go about creating a completely custom UI that should stay in sync with other editors?

---

_[View the full topic](https://discuss.codemirror.net/t/codemirror-6-proper-way-to-listen-for-changes/2395)._
