Skip to content
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

onError do nothing #17

Closed
zbyso23 opened this issue Oct 8, 2019 · 13 comments
Closed

onError do nothing #17

zbyso23 opened this issue Oct 8, 2019 · 13 comments
Labels
help wanted Extra attention is needed

Comments

@zbyso23
Copy link

zbyso23 commented Oct 8, 2019

I try to use onError, but do nothing, and when I look to implementation - is logically then do nothing because is not implemented :)
is planned to implement this useful property? thanks

@vankop
Copy link
Owner

vankop commented Oct 8, 2019

@zbyso23 PR wellcome.

@vankop vankop added the help wanted Extra attention is needed label Oct 8, 2019
@zbyso23
Copy link
Author

zbyso23 commented Oct 10, 2019

@zbyso23 PR wellcome.

okay, how to? I don't have experience with collaboration on GitHub project, trying create new branch - handle-errors but commit is impossible - don't have correct access rights

@emmanuelgautier
Copy link
Contributor

You have to fork this project, then push the new branch you created into your newly created repo. After that, you should be able to create a new PR from the Github interface.

@ngmgit
Copy link

ngmgit commented Oct 31, 2019

If you are using ace mode then for now you can have onChangeText callback and have a debounced function, if needed, to get the errors from ace session.

<jsonEditorRef>.current.jsonEditor.aceEditor.getSession().getAnnotations();

And a better way is to subscribe to 'changeAnnotation' event for ace.

@zbyso23
Copy link
Author

zbyso23 commented Feb 5, 2020

thanks - I try to implement subscribe changeAnnotation, but I noticed strange behaviour of Ace editor - when is fired in callback, return empty object - but, I say "okay, I get manually", but when i call directly code like this:

const annotations = this.jsonEditor.aceEditor.getSession().getAnnotations();

in annotations return OLD error! then I fix for now by code like this:

setTimeout(() => {
   const annotations = this.jsonEditor.aceEditor.getSession().getAnnotations();
}, 150);

but is very dirty - time can be not enough on old computers :/
thrid issue what i registrer, even i call this code only once:

this.jsonEditor.aceEditor.getSession().on('changeAnnotation', this.handleError);

is every time called twice...
if anybody notice similar behaviour i very thanks for any help :)

@vankop
Copy link
Owner

vankop commented Feb 5, 2020

@zbyso23 You need to create issue in upstream dependency

@zbyso23
Copy link
Author

zbyso23 commented Jun 10, 2020

I use now this hack

    handleChange() {
        if (this.props.onChange) {
            try {
                const text = this.jsonEditor.getText();
                if (text === '') {
                    this.props.onChange(null);
                }

                const currentJson = this.jsonEditor.get();
                if (this.props.value !== currentJson) {
                    this.props.onChange(currentJson);
                }
            } catch (err) {
                this.err = err;
                if(this.props.onError) {
                  const error = typeof err === 'object' ? err.message : err;
                  this.props.onError(error);
                }
            }
        }
    }

works good

@zbyso23
Copy link
Author

zbyso23 commented Jun 10, 2020

for even handling ACE Editor errors prepared this ugly version, please don't beat me 😄

import React, { Component } from 'react';
import PropTypes from 'prop-types';
import JSONEditor from 'jsoneditor/dist/jsoneditor';
import 'jsoneditor/dist/jsoneditor.css';
// import './fixAce.css';

/**
 * @typedef {{
 * tree: string,
 * view: string,
 * form: string,
 * code: string,
 * text: string,
 * allValues: Array<string>
 * }} TJsonEditorModes
 */
const modes = {
    tree: 'tree',
    view: 'view',
    form: 'form',
    code: 'code',
    text: 'text'
};

const values = Object.values(modes);

const hashCodeACE = s => s.split("").reduce(function(a,b){a=((a<<5)-a)+b.charCodeAt(0);return a&a},0);              

modes.allValues = values;

/**
 * @type {object}
 * @property {object} [value]
 * @property {string} [mode='tree'] - Set the editor mode.
 * @property {string} [name=undefined] - Initial field name for the root node
 * @property {object} [schema] - Validate the JSON object against a JSON schema.
 * @property {object} [schemaRefs] - Schemas that are referenced using
 * the $ref property
 * @property {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.
 * Return new json.
 * @property {Function} [onError] - 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.
 * @property {Function} [onErrorAce] - Set a callback function triggered when an error of ACEditor occurs.
 * @property {Function} [onModeChange] - Set a callback function
 * triggered right after the mode is changed by the user.
 * @property {object} [ace] - Provide a version of the Ace editor.
 * Only applicable when mode is code
 * @property {object} [ajv] - Provide a instance of ajv,
 * the library used for JSON schema validation.
 * @property {string} [theme] - Set the Ace editor theme,
 * uses included 'ace/theme/jsoneditor' by default.
 * @property {boolean} [history=false] - Enables history,
 * adds a button Undo and Redo to the menu of the JSONEditor. Only applicable when
 * mode is 'tree' or 'form'
 * @property {boolean} [navigationBar=true] - Adds navigation bar to the menu
 * the navigation bar visualize the current position on the
 * tree structure as well as allows breadcrumbs navigation.
 * @property {boolean} [statusBar=true] - Adds status bar to the buttom of the editor
 * the status bar shows the cursor position and a count of the selected characters.
 * Only applicable when mode is 'code' or 'text'.
 * @property {boolean} [search=true] - Enables a search box in
 * the upper right corner of the JSONEditor.
 * @property {Array<string>} [allowedModes] - Create a box in the editor menu where
 * the user can switch between the specified modes.
 * @property {(string|PropTypes.elementType)} [tag='div'] - Html element, or react element to render
 * @property {object} [htmlElementProps] - html element custom props
 * @property {Function} [innerRef] - callback to get html element reference
 */
export default class JsonEditorACE extends Component {
    constructor(props) {
        super(props);

        this.htmlElementRef = null;
        this.jsonEditor = null;

        this.handleChange = this.handleChange.bind(this);
        this.handleErrorACE = this.handleErrorACE.bind(this);
        this.setRef = this.setRef.bind(this);
        this.collapseAll = this.collapseAll.bind(this);
        this.expandAll = this.expandAll.bind(this);
        this.focus = this.focus.bind(this);

        this.lastErrorACE = null;
        this.lastErrorACEHash = '';
    }

    componentDidMount() {
        const {
            allowedModes,
            innerRef,
            htmlElementProps,
            tag,
            onChange,
            onErrorAce,
            ...rest
        } = this.props;

        this.createEditor({
            ...rest,
            modes: allowedModes
        });
    }

    // eslint-disable-next-line react/sort-comp
    componentDidUpdate({
        allowedModes,
        schema,
        name,
        theme,
        schemaRefs,
        innerRef,
        htmlElementProps,
        tag,
        onChange,
        ...rest
    }) {
        if (this.jsonEditor) {
            if (theme !== this.props.theme) {
                this.createEditor({
                    ...rest,
                    theme,
                    modes: allowedModes
                });
            } else {
                if (schema !== this.props.schema
                    || schemaRefs !== this.props.schemaRefs
                ) {
                    this.jsonEditor.setSchema(schema, schemaRefs);
                }

                if (name !== this.jsonEditor.getName()) {
                    this.jsonEditor.setName(name);
                }
            }
        }
    }

    shouldComponentUpdate({ htmlElementProps }) {
        return htmlElementProps !== this.props.htmlElementProps;
    }

    componentWillUnmount() {
        if (this.jsonEditor) {
            this.jsonEditor.destroy();
            this.jsonEditor = null;
        }
    }

    setRef(element) {
        this.htmlElementRef = element;
        if (this.props.innerRef) {
            this.props.innerRef(element);
        }
    }

    createEditor({ value, ...rest }) {
        if (this.jsonEditor) {
            this.jsonEditor.destroy();
        }
        this.jsonEditor = new JSONEditor(this.htmlElementRef, {
            onChange: this.handleChange,
            onError: this.handleErrorACE,
            ...rest
        });
        this.jsonEditor.set(value);
        if(this.jsonEditor && this.jsonEditor.aceEditor)
        {
          this.jsonEditor.aceEditor.getSession().on('changeAnnotation', this.handleErrorACE);
        }
        window['jsoneditor'] = this.jsonEditor;
    }

    handleChange() {
        if (this.props.onChange) {
            try {
                const text = this.jsonEditor.getText();
                if (text === '') {
                    this.props.onChange(null);
                }

                const currentJson = this.jsonEditor.get();
                if (this.props.value !== currentJson) {
                    this.props.onChange(currentJson);
                }
            } catch (err) {
                this.err = err;
                if(this.props.onError) {
                  const error = typeof err === 'object' ? err.message : err;
                  this.props.onError(error);
                }
            }
        }
    }

    handleErrorACE() {
        if(!this.jsonEditor || !this.props.onErrorAce) return;
        const deltaTreshold = 200;
        const handleErrorDelta = (this.lastErrorACE) ? (new Date().getTime()) - this.lastErrorACE : 0;
        try {
            if(this.jsonEditor.aceEditor)
            {
              setTimeout(() => {
                if(!this.jsonEditor || !this.jsonEditor.aceEditor) return;
                const annotations = this.jsonEditor.aceEditor.getSession().getAnnotations();
                const errors = annotations.filter(annot => annot.type === 'error').map(annot => {
                  return { ...annot, message: `${annot.text} on line ${annot.row} and column ${annot.column}` }
                });
                if (errors.length > 0) {
                  const errorHash = hashCodeACE(JSON.stringify(errors));
                  if(handleErrorDelta < deltaTreshold && errorHash === this.lastErrorACEHash) return;
                  this.lastErrorACEHash = errorHash;
                  this.props.onErrorAce(errors);
                }
              }, deltaTreshold);
            }
        } catch (err) {
            this.err = err;
        }
        this.lastErrorACE = new Date().getTime();
    }

    collapseAll() {
        if (this.jsonEditor) {
            this.jsonEditor.collapseAll();
        }
    }

    expandAll() {
        if (this.jsonEditor) {
            this.jsonEditor.expandAll();
        }
    }

    focus() {
        if (this.jsonEditor) {
            this.jsonEditor.focus();
        }
    }

    render() {
        const {
            htmlElementProps,
            tag
        } = this.props;

        return React.createElement(
            tag,
            {
                ...htmlElementProps,
                ref: this.setRef
            }
        );
    }
}

JsonEditorACE.propTypes = {
    //  jsoneditor props
    value: PropTypes.oneOfType([PropTypes.object, PropTypes.array]),
    mode: PropTypes.oneOf(values),
    name: PropTypes.string,
    schema: PropTypes.object,
    schemaRefs: PropTypes.object,

    onChange: PropTypes.func,
    onError: PropTypes.func,
    onErrorAce: PropTypes.func,
    onModeChange: PropTypes.func,

    ace: PropTypes.object,
    ajv: PropTypes.object,
    theme: PropTypes.string,
    history: PropTypes.bool,
    navigationBar: PropTypes.bool,
    statusBar: PropTypes.bool,
    search: PropTypes.bool,
    allowedModes: PropTypes.arrayOf(PropTypes.oneOf(values)),

    //  custom props
    tag: PropTypes.oneOfType([PropTypes.string, PropTypes.elementType]),
    htmlElementProps: PropTypes.object,
    innerRef: PropTypes.func,
};

JsonEditorACE.defaultProps = {
    tag: 'div',
    mode: modes.tree,
    history: false,
    search: true,
    navigationBar: true,
    statusBar: true,
};

/**
 * @type TJsonEditorModes
 */
JsonEditorACE.modes = modes;

@vankop
Copy link
Owner

vankop commented Jun 10, 2020

PR welcome

@vankop
Copy link
Owner

vankop commented Nov 25, 2020

in jsoneditor@9 there is an option onError, so current prop onError will be passed in editor options

@vankop vankop closed this as completed Nov 25, 2020
@AnnaRainier
Copy link

this onError method fires on my component only if I trigger "filter, sort or transform contents" manually, I expected it to fire once an error occurs in JSON file. If I need to rely on JSON validity state, for, let's say, some button disabled state, how do I do that?

@zbyso23
Copy link
Author

zbyso23 commented Jan 25, 2022

I solve this problem by code above (10 Jun 2020), but it's not part of current code - i use standalone file Editor.tsx in my project

@Isaacgl68
Copy link

you can use the onValidationError of the json editor
You just need to add it in the editor props (it will pass to the jeson editor as the editor is passing the ...rest props)

const onValidationError = (value)=>{
if (value && value.length > 0) {
//do
}
}
<Editor
...
onValidationError={onValidationError} />

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
help wanted Extra attention is needed
Projects
None yet
Development

No branches or pull requests

6 participants