-
Notifications
You must be signed in to change notification settings - Fork 112
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
Programmatic changes do not trigger 'onChange' #318
Comments
Thanks for reporting. The onChange in your example indeed doesn't work. Can you simplify the demo further? I started from a bare bone JS demo testing https://jsbin.com/jimehuh/edit?html,output UPDATE: I had an error in my demo, method |
Can you strip the demo of the issue further so we can triangulate the issue? Can you also update to use the latest version of the library? You're demo uses |
The issue may be related to your example making a nested change in the existing |
Hey, I've created a new vanilla js & latest version of vanilla-jsoneditor & minimal reproduction, see: https://github.com/cloydlau/reproduction.git |
I've experimented with implementing support for mutating JSON objects. The editor is built around the assumption that the data is immutable. This has a number of big memory and performance advantages. Without immutability, the editor will have to make a full copy of the document with every change that is made, and it will have to re-render the full document as well. With immutable objects, it only has to render the changed parts and does not have to create deep copies. What I can do is create an option |
I've created a PR testing this out with a new option An other option would be to just document the current behavior and explain that you should not mutate your data. |
According to the test results, the issue seems not fully solved by that PR. <input type="text" onchange="onInputChange()">
<button onclick="setInputValue()">set input value</button>
<script>
function onInputChange () {
console.log('onInputChange')
}
function setInputValue () {
document.querySelector('input').value = Math.random()
}
</script> Could you elaborate further on this: 'The editor is built around the assumption that the data is immutable'? |
Thanks for your thorough testing. The idea is that
In Svelte, mutating an object like |
💡 One thing I can try out is turning off |
Actually I tested within Svelte environment (with your codebase). <script>
import { JSONEditor } from '../../../src/lib'
let jsonEditorRef
let content = { json: { a: 1 } }
function onClick() {
content.json.a = Math.random()
console.log(jsonEditorRef.get()) // will get new value, but UI doesn't rerender
}
</script>
<button on:click={onClick}>directly mutate content</button>
<JSONEditor
bind:this={jsonEditorRef}
bind:content
/> |
The code base of |
I've fixed the issue with |
Not to hijack this Issue, but I actually would like a way to programmatically modify the JSONEditor contents without triggering an |
@MitchBuell I think you are looking for this idea (not yet implemented): #145 |
I've been thinking a bit more about a solution to support mutable changes. I see two main challenges:
In conclusion: if we want to support mutations, we do need to make a copy of the document on every change to support undo/redo and onChange events. Internally, the library can keep using an immutable API. The immutable API is performant and suitable for large documents. The mutable API can be enabled with a configuration option and is suitable for small documents. So, I think my earlier experiment #332 is in the right direction and we can work that out in detail. I think it will enable the best of both worlds. |
I personally believe that undo/redo is primarily intended for user interactions rather than programmatic changes. Undo/redo for programmatic changes can also be handled programmatically.
The doc says: 'both changes made by a user and programmatic changes made via methods like .set(), .update(), or .patch()', but it does not specify the reason for that. Other than the use case mentioned in #128, it seems that triggering the 'onChange' event when making programmatic changes is not a mainstream practice (such as the native input element). Is it a possible solution to disregard undo/redo and onChange event when making programmatic changes? |
I think we're discussing two interesting points here, maybe best to keep them separate:
The reason for triggering
I think that would be problematic and lead to an odd and furstrating user experience: sometimes you can undo, sometimes you can't. But I don't think it would solve the issue of supporting mutable changes. |
OK, let's keep them separate: 1. mutable changes
I think the current behavior is the expected behavior, mutable changes support is not necessary. 2. triggering onChange for programmatic changes or not
The current behavior is problematic whether we trigger or not. I think there are 3 solutions for this:
3. undo/redo
I think user can always undo/redo when there're only user operations. Programmatical changes are system behaviors and should be treated separately from user operations. I mean, user can undo/redo what they have done, they should not undo/redo what they have not done. |
Thanks for the update. My action points for now are:
About the undo/redo: the user must be able to undo programmatic changes, else the whole thing doesn't work. Suppose the user has a list with 20 names, and edits the 16th. Then, programmatically, the last 10 names are removed from the list, leaving only the first 10 names. If the user wants to undo his only change (renaming the 16th name), he will first have to undo removing the last 10 names from the list, because the 16th name doesn't exist after the programmatic change. |
#332 is now working. I'm still a bit unsure about what will be the best default value for the new option In the PR right now, when creating the editor, it will by default use |
I personally believe the mutable change support is unnecessary.
I suggest adopting either solution 2 or 3. And document the behavior. |
As far as I can see, it is necessary to support history (undo/redo), and help Svelte optimize by rendering only changed parts of the UI. And an editor without undo/redo is not acceptable to me, that is really necessary for a good user experience. If you know of an alternative solution please let me know, the deep copying is far from ideal. #332 does not address changing when |
I'm a bit confused: the mutable support is necessary to get the following part from your example working: <button
@click="
() => {
content.json.greeting = Math.random(); // <-- mutable change
editor.set(content);
}
"
> |
Yes that's the current behavior of 'set with mutated json', but not necessarily the expected behavior.
Solution 1 indeed need mutable support, but solution 2 or 3 seem not. |
I'm not sure whether we're on the same page. There are two things that I want to address:
So #410 will address the "onChange triggered" issue, and #332 will address the "UI re-rendered" issue. Does that make sense? |
I think this means the mutations to the data won't trigger UI re-render directly, but it's maybe a different story when we explicitly call the set/update/patch methods. I think there are two solutions:
|
Thanks for thinking along Cloyd. Some thoughts:
Ok, I'll merge #410 now and update the docs explaining about immutability. |
I've just published |
Hello Jos,
The doc says 'The onChange callback which is invoked on every change of the contents, both changes made by a user and programmatic changes made via methods like .set(), .update(), or .patch()'.
But now it isn't, so is it intended or a bug?
Reproduction Link: https://codesandbox.io/s/svelte-jsoneditor-vue-forked-gp453r?file=/src/components/VueJSONEditor.vue
And another problem is that if I replace the
set
method in the Reproduction Link withupdate
, the view won't update.The text was updated successfully, but these errors were encountered: