DraftJS triggers content change on focus?
Asked Answered
H

3

9

I have an editor on a page and save button. I want save button only to appear if there are changes (since last save). So, when you save, i set this.setState({hasChanges: false}) and in onChange function i set hasChanges to true.

And that's all working fine. The issue is that editor will fire onChange event when editor gain focus (but content is not changed yet). And, that is expected behaviour according to their documentation

The event listeners within the component will observe focus changes and propagate them through onChange as expected, so state and DOM will remain correctly in sync.

Is there some way to know if content has changed inside onChange method, or only selection is changed?

Hankering answered 1/12, 2016 at 13:12 Comment(0)
E
14

I posted this answer to your question on github earlier today, but I'll add it here as well for future reference:

You're right in that onChange is called every time the editorState changes. And since the editorState holds both the selectionState and the contentState, it will change both when there's a content edit, and when the selection/focus changes.

If you want to know if the change that triggered the onChange method was in the contentState or in the selectionState, you could compare them with their old values:

function onChange(newState) {
  const currentContentState = this.state.editorState.getCurrentContent()
  const newContentState = newState.getCurrentContent()

  if (currentContentState !== newContentState) {
    // There was a change in the content  
  } else {
    // The change was triggered by a change in focus/selection
  }
}

Now, if you know that the change was in the contentState, you can get some more info by calling newState.getLastChangeType(). It should return any of these values (unless you, or some plugin you've added, have created new change types).

Endodermis answered 1/12, 2016 at 21:31 Comment(2)
This test is invalid, for example when using insertDataBlock() the equality remains true, while the content HAS actually changed. You should deep-compoare the objects.Booty
This doesn't detect some style changes done by toolbarAreopagite
A
2

However, sometimes just the conditional if (currentContentState !== newContentState) not work and not detect the change for cases like when you to modify the content state using Entity.mergeData together with forceSelection because this change is stored inside entity and is not exposed in contentState.

So you could do something like that additionaly.

this.currentEntityMap = null;

function onChange(newEditorState) {

 const currentContentState = editorState.getCurrentContent();
 const newContentState = newEditorState.getCurrentContent();
 const newContentStateRaw = convertToRaw(newContentState);
 const newEntityMap = newContentStateRaw ? newContentStateRaw.entityMap : null;

//so if you have the two entity maps, you can to compare it, here an example function.
 const isEntityMapChanged = this.isEntityMapChanged(newEntityMap);

 this.currentEntityMap = newEntityMap;  
}

 isEntityMapChanged(newEntityMap) {
        let isChanged = false;
        if (this.currentEntityMap) {
            loop1:
            for (const index of Object.keys(newEntityMap)) {
                if (this.currentEntityMap[index] && newEntityMap[index].type === this.currentEntityMap[index].type) {
                    loop2:
                    for (const prop of Object.keys(newEntityMap[index].data)) {
                        if (newEntityMap[index].data[prop] !== this.currentEntityMap[index].data[prop]) {
                            isChanged = true;
                            break loop1;
                        }
                    }
                } else {
                    isChanged = true;
                    break loop1;
                }
            }
        }

        return isChanged;
    }

then to used the flag isEntityMapChanged and the first conditional for to do the save.

Antihero answered 9/5, 2018 at 21:10 Comment(0)
M
1

you should use code follow:

  const onChange = newState => {
    if (
      // when content change or line style change will change the state
      !newState.getCurrentContent().equals(editorState.getCurrentContent()) ||
      !newState
        .getCurrentInlineStyle()
        .equals(editorState.getCurrentInlineStyle())
    ) {
      setEditorState(newState);
    }
  };

if you just use content equal ,then line style change will not on effect.

Mccully answered 25/9, 2020 at 3:17 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.