Implemented options `onChangeJSON(json)` and `onChangeText(jsonString)`

This commit is contained in:
jos 2018-08-07 11:03:27 +02:00
parent d1ac1cb694
commit 983fafdf9c
9 changed files with 131 additions and 40 deletions

View File

@ -5,8 +5,13 @@ https://github.com/josdejong/jsoneditor
## not yet released, version 5.20.0 ## not yet released, version 5.20.0
_Good news: JSONEditor is finally framework friendly and can now be easily
integrated in React, Vue, and Angular!_
- Implemented new methods `update` and `updateText`, which maintain the state - Implemented new methods `update` and `updateText`, which maintain the state
of the editor (expanded nodes, search, selection). of the editor (expanded nodes, search, selection). This makes it easy to
integrate in frameworks like React.
- Implemented options `onChangeJSON(json)` and `onChangeText(jsonString)`.
## 2018-08-02, version 5.19.2 ## 2018-08-02, version 5.19.2

View File

@ -48,11 +48,30 @@ Constructs a new JSONEditor.
} }
``` ```
- `{function} onChange` - `{function} onChange()`
Set a callback function triggered when the contents of the JSONEditor change. Called without parameters. Will only be triggered on changes made by the user, not in case of programmatic changes via the functions `set`, `setText`, `update`, or `updateText`. Set a callback function triggered when the contents of the JSONEditor change.
This callback does not pass the changed contents, use `get()` or `getText()` for that.
Note that `get()` can throw an exception in mode `text` or `code`, when the editor contains invalid JSON.
Will only be triggered on changes made by the user, not in case of programmatic changes via the functions `set`, `setText`, `update`, or `updateText`.
See also callback functions `onChangeJSON(json)` and `onChangeText(jsonString)`.
- `{function} onEditable` - `{function} onChangeJSON(json)`
Set a callback function triggered when the contents of the JSONEditor change.
Passes the changed contents as a JSON object.
Only applicable when option `mode` is `tree`, `form`, or `view`.
The callback will only be triggered on changes made by the user, not in case of programmatic changes via the functions `set`, `setText`, `update`, or `updateText`.
See also callback function `onChangeText(jsonString)`.
- `{function} onChangeText(jsonString)`
Set a callback function triggered when the contents of the JSONEditor change.
Passes the changed contents as a stringified JSON object.
The callback will only be triggered on changes made by the user, not in case of programmatic changes via the functions `set`, `setText`, `update`, or `updateText`.
See also callback function `onChangeJSON(json)`.
- `{function} onEditable(node)`
Set a callback function to determine whether individual nodes are editable or read-only. Only applicable when option `mode` is `tree`, `text`, or `code`. Set a callback function to determine whether individual nodes are editable or read-only. Only applicable when option `mode` is `tree`, `text`, or `code`.
@ -60,7 +79,7 @@ Constructs a new JSONEditor.
In modes `text` and `code`, the callback is invoked as `editable(node)` where `node` is an empty object (no field, value, or path). In that case the function can return false to make the text or code editor completely read-only. In modes `text` and `code`, the callback is invoked as `editable(node)` where `node` is an empty object (no field, value, or path). In that case the function can return false to make the text or code editor completely read-only.
- `{function} onError` - `{function} onError(error)`
Set a callback function triggered when an error occurs. Invoked with the error as first argument. The callback is only invoked Set a callback function triggered when an error occurs. Invoked with the error as first argument. The callback is only invoked
for errors triggered by a users action, like switching from code mode to tree mode or clicking the Format button whilst the editor doesn't contain valid JSON. for errors triggered by a users action, like switching from code mode to tree mode or clicking the Format button whilst the editor doesn't contain valid JSON.
@ -459,7 +478,7 @@ See also `JSONEditor.set(json)`.
Replace text data when the new data contains changes. Replace text data when the new data contains changes.
In modes `tree`, `form`, and `view`, the state of the editor will be maintained (expanded nodes, search, selection). In modes `tree`, `form`, and `view`, the state of the editor will be maintained (expanded nodes, search, selection).
See also `JSONEditor.setText(json)`. See also `JSONEditor.setText(jsonString)`.
This method throws an exception when the provided jsonString does not contain This method throws an exception when the provided jsonString does not contain
valid JSON and the editor is in mode `tree`, `view`, or `form`. valid JSON and the editor is in mode `tree`, `view`, or `form`.

View File

@ -23,14 +23,32 @@
<body> <body>
<p> <p>
Keep two editors synchronized using <code>onChange</code> and <code>update</code>. Keep two editors synchronized using <code>onChangeText</code> and <code>updateText</code>.
</p>
<p>
This can be done too with <code>onChangeJSON</code> and <code>update</code>, which can only be used in
modes <code>tree</code>, <code>form</code> (and <code>view</code>).
</p> </p>
<div id="jsoneditor1"></div> <div id="jsoneditor1"></div>
<div id="jsoneditor2"></div> <div id="jsoneditor2"></div>
<script> <script>
// create editor 1
var editor1 = new JSONEditor(document.getElementById('jsoneditor1'), {
onChangeText: function (jsonString) {
editor2.updateText(jsonString);
}
});
// create editor 2
var editor2 = new JSONEditor(document.getElementById('jsoneditor2'), {
onChangeText: function (jsonString) {
editor1.updateText(jsonString);
}
});
// set initial data in both editors
var json = { var json = {
'array': [1, 2, 3], 'array': [1, 2, 3],
'boolean': true, 'boolean': true,
@ -39,21 +57,7 @@
'object': {'a': 'b', 'c': 'd'}, 'object': {'a': 'b', 'c': 'd'},
'string': 'Hello World' 'string': 'Hello World'
}; };
// create editor 1
var editor1 = new JSONEditor(document.getElementById('jsoneditor1'), {
onChange: function () {
editor2.update(editor1.get());
}
});
editor1.set(json); editor1.set(json);
// create editor 2
var editor2 = new JSONEditor(document.getElementById('jsoneditor2'), {
onChange: function () {
editor1.update(editor2.get());
}
});
editor2.set(json); editor2.set(json);
</script> </script>

View File

@ -1,6 +1,6 @@
import React, { Component } from 'react'; import React, { Component } from 'react';
import JSONEditorDemo from "./JSONEditorDemo"; import JSONEditorDemo from './JSONEditorDemo';
import './App.css'; import './App.css';
class App extends Component { class App extends Component {
@ -27,7 +27,7 @@ class App extends Component {
</div> </div>
<JSONEditorDemo <JSONEditorDemo
json={this.state.json} json={this.state.json}
onChange={this.onChange} onChangeJSON={this.onChangeJSON}
/> />
<div className="code"> <div className="code">
<pre> <pre>
@ -41,7 +41,7 @@ class App extends Component {
); );
} }
onChange = (json) => { onChangeJSON = (json) => {
this.setState({ json }); this.setState({ json });
}; };

View File

@ -9,8 +9,7 @@ export default class JSONEditorDemo extends Component {
componentDidMount () { componentDidMount () {
const options = { const options = {
mode: 'tree', mode: 'tree',
modes: ['tree', 'code'], onChangeJSON: this.props.onChangeJSON
onChange: this.onChange
}; };
this.jsoneditor = new JSONEditor(this.container, options); this.jsoneditor = new JSONEditor(this.container, options);
@ -32,13 +31,4 @@ export default class JSONEditorDemo extends Component {
<div className="jsoneditor-react-container" ref={elem => this.container = elem} /> <div className="jsoneditor-react-container" ref={elem => this.container = elem} />
); );
} }
onChange = () => {
if (this.props.onChange) {
// note that this.jsoneditor.get() can fail in mode text/code
// when the contents is no valid JSON object.
// So if you need mode text/node, you must use getText() and setText().
this.props.onChange(this.jsoneditor.get());
}
}
} }

View File

@ -20,7 +20,20 @@ var util = require('./util');
* 'tree' (default), 'view', * 'tree' (default), 'view',
* 'form', 'text', and 'code'. * 'form', 'text', and 'code'.
* {function} onChange Callback method, triggered * {function} onChange Callback method, triggered
* on change of contents * on change of contents.
* Does not pass the contents itself.
* See also `onChangeJSON` and
* `onChangeText`.
* {function} onChangeJSON Callback method, triggered
* in modes on change of contents,
* passing the changed contents
* as JSON.
* Only applicable for modes
* 'tree', 'view', and 'form'.
* {function} onChangeText Callback method, triggered
* in modes on change of contents,
* passing the changed contents
* as stringified JSON.
* {function} onError Callback method, triggered * {function} onError Callback method, triggered
* when an error occurs * when an error occurs
* {Boolean} search Enable search box. * {Boolean} search Enable search box.
@ -87,6 +100,14 @@ function JSONEditor (container, options, json) {
delete options.editable; delete options.editable;
} }
// warn if onChangeJSON is used when mode can be `text` or `code`
if (options.onChangeJSON) {
if (options.mode === 'text' || options.mode === 'code' ||
(options.modes && (options.modes.indexOf('text') !== -1 || options.modes.indexOf('code') !== -1))) {
console.warn('Option "onChangeJSON" is not applicable to modes "text" and "code". Use "onChangeText" instead.');
}
}
// validate options // validate options
if (options) { if (options) {
Object.keys(options).forEach(function (option) { Object.keys(options).forEach(function (option) {
@ -125,7 +146,8 @@ JSONEditor.prototype.DEBOUNCE_INTERVAL = 150;
JSONEditor.VALID_OPTIONS = [ JSONEditor.VALID_OPTIONS = [
'ajv', 'schema', 'schemaRefs','templates', 'ajv', 'schema', 'schemaRefs','templates',
'ace', 'theme','autocomplete', 'ace', 'theme','autocomplete',
'onChange', 'onEditable', 'onError', 'onModeChange', 'onSelectionChange', 'onTextSelectionChange', 'onChange', 'onChangeJSON', 'onChangeText',
'onEditable', 'onError', 'onModeChange', 'onSelectionChange', 'onTextSelectionChange',
'escapeUnicode', 'history', 'search', 'mode', 'modes', 'name', 'indentation', 'escapeUnicode', 'history', 'search', 'mode', 'modes', 'name', 'indentation',
'sortObjectKeys', 'navigationBar', 'statusBar', 'languages', 'language' 'sortObjectKeys', 'navigationBar', 'statusBar', 'languages', 'language'
]; ];

View File

@ -20,8 +20,12 @@ var DEFAULT_THEME = 'ace/theme/jsoneditor';
* or "code". * or "code".
* {Number} indentation Number of indentation * {Number} indentation Number of indentation
* spaces. 2 by default. * spaces. 2 by default.
* {function} onChange Callback method * {function} onChange Callback method triggered on change.
* triggered on change * Does not pass the changed contents.
* {function} onChangeText Callback method, triggered
* in modes on change of contents,
* passing the changed contents
* as stringified JSON.
* {function} onModeChange Callback method * {function} onModeChange Callback method
* triggered after setMode * triggered after setMode
* {function} onEditable Determine if textarea is readOnly * {function} onEditable Determine if textarea is readOnly
@ -330,6 +334,16 @@ textmode._onChange = function () {
console.error('Error in onChange callback: ', err); console.error('Error in onChange callback: ', err);
} }
} }
// trigger the onChangeText callback
if (this.options.onChangeText) {
try {
this.options.onChangeText(this.getText());
}
catch (err) {
console.error('Error in onChangeText callback: ', err);
}
}
}; };
/** /**

View File

@ -33,7 +33,18 @@ var treemode = {};
* {Boolean} history Enable history (undo/redo). * {Boolean} history Enable history (undo/redo).
* True by default * True by default
* {function} onChange Callback method, triggered * {function} onChange Callback method, triggered
* on change of contents * on change of contents.
* Does not pass the changed contents.
* {function} onChangeJSON Callback method, triggered
* in modes on change of contents,
* passing the changed contents
* as JSON.
* Only applicable for modes
* 'tree', 'view', and 'form'.
* {function} onChangeText Callback method, triggered
* in modes on change of contents,
* passing the changed contents
* as stringified JSON.
* {String} name Field name for the root node. * {String} name Field name for the root node.
* {boolean} escapeUnicode If true, unicode * {boolean} escapeUnicode If true, unicode
* characters are escaped. * characters are escaped.
@ -461,6 +472,26 @@ treemode._onChange = function () {
console.error('Error in onChange callback: ', err); console.error('Error in onChange callback: ', err);
} }
} }
// trigger the onChangeJSON callback
if (this.options.onChangeJSON) {
try {
this.options.onChangeJSON(this.get());
}
catch (err) {
console.error('Error in onChangeJSON callback: ', err);
}
}
// trigger the onChangeText callback
if (this.options.onChangeText) {
try {
this.options.onChangeText(this.getText());
}
catch (err) {
console.error('Error in onChangeText callback: ', err);
}
}
}; };
/** /**

View File

@ -51,6 +51,12 @@
onChange: function () { onChange: function () {
console.log('change'); console.log('change');
}, },
onChangeJSON: function (json) {
console.log('onChangeJSON', json);
},
onChangeText: function (text) {
console.log('onChangeText', text);
},
indentation: 4, indentation: 4,
escapeUnicode: true escapeUnicode: true
}; };