codex-team / editor.js

A block-style editor with clean JSON output
https://editorjs.io
Apache License 2.0
28.54k stars 2.08k forks source link

<select /> not triggering editor.onChange #1027

Closed mcnamee closed 4 years ago

mcnamee commented 4 years ago

I've created a custom plugin which has an <input /> and a <select />. The editor.onChange method correctly triggers on when the input changes, however does not on select change.

I could be wrong, but is it because of this?

The event.listener is looking for a select emitting an 'input' event (whereas it should be looking for a 'change' event?).

robonetphy commented 4 years ago

Hi @mcnamee, I have checked with below Class it's working as expected i.e. it's calling onchange each time select value changes.

`

    class SelectMenu {
  static get toolbox() {
    return {

      title: 'Select',
      icon: '<svg width="17" height="15" viewBox="0 0 336 276" xmlns="http://www.w3.org/2000/svg"><path d="M291 150V79c0-19-15-34-34-34H79c-19 0-34 15-34 34v42l67-44 81 72 56-29 42 30zm0 52l-43-30-56 30-81-67-66 39v23c0 19 15 34 34 34h178c17 0 31-13 34-29zM79 0h178c44 0 79 35 79 79v118c0 44-35 79-79 79H79c-44 0-79-35-79-79V79C0 35 35 0 79 0z"/></svg>'
    };
  }

  constructor({ data }) {
    this.data = data;
  }

  render() {
    const wrapper = document.createElement('div');
    const input = document.createElement('select');

    var option = document.createElement("option");
    option.setAttribute("value", "option1");
    var textOption = document.createTextNode("option1");
    option.appendChild(textOption);
    input.appendChild(option);

    option = document.createElement("option");
    option.setAttribute("value", "option2");
    textOption = document.createTextNode("option2");
    option.appendChild(textOption);
    input.appendChild(option);

    option = document.createElement("option");
    option.setAttribute("value", "option3");
    textOption = document.createTextNode("option3");
    option.appendChild(textOption);
    input.appendChild(option);
    wrapper.appendChild(input);

    return wrapper;
  }

  save(blockContent) {
    const input = blockContent.querySelector('select');

    return {
      selectValue: input.value
    }
  }
}`

So can you Share Example for which your class not working?

robonetphy commented 4 years ago

Hi @mcnamee, So can we close this issue?

robonetphy commented 4 years ago

The issue was not reproducible in Editor.js v2.18.So, we are closing this issue. But can reopen the issue if it occurs.

thucne commented 2 years ago

Hmm, I'm facing this issue rn, I had tried with text-area, and it worked, but not for select tag...
I need the onChange function triggered every time the selected value changes.

Thanks in advance!

new Editor({
    ...otherProps,
    onChange: handleOnChange 
})

My code:

export default class CodeEditor {
    // This plugin allows to write code and select language
    static get toolbox() {
        return {
            title: 'New Raw Code',
            icon: '<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6"><path stroke-linecap="round" stroke-linejoin="round" d="M17.25 6.75L22.5 12l-5.25 5.25m-10.5 0L1.5 12l5.25-5.25m7.5-3l-4.5 16.5" /></svg>'
        };
    }

    static get isReadOnlySupported() {
        return true;
    }

    constructor({ data, config, api, readOnly }) {
        this.api = api;
        this.readOnly = readOnly;
        this.data = {
            language: data.language || 'javascript',
            code: data.code || ''
        };
    }

    render() {
        // include a language selector and a code editor
        this._element = document.createElement('div');
        this._element.classList.add('code-editor');

        // flex-col 
        this._element.style.display = 'flex';
        this._element.style.flexDirection = 'column';

        // language selector
        this.languageSelector = document.createElement('select');
        this.languageSelector.classList.add('language-selector');
        this.languageSelector.style.marginBottom = '10px';
        this.languageSelector.style.padding = '5px';
        this.languageSelector.style.borderRadius = '5px';
        this.languageSelector.style.border = '1px solid #ccc';
        this.languageSelector.style.outline = 'none';
        this.languageSelector.style.fontSize = '14px';
        this.languageSelector.style.fontFamily = 'monospace';
        this.languageSelector.style.width = '100px';

        let option;
        let textOption;
        // add languages
        supportedLanguages.map(language => {
            option = document.createElement('option');
            option.setAttribute('value', language);
            textOption = document.createTextNode(language);
            option.appendChild(textOption);
            this.languageSelector.appendChild(option);
        })

        // if data is present, set the language
        if (this.data.language) {
            this.languageSelector.value = this.data.language;
        }

        // code editor
        this._editor = document.createElement('textarea');
        this._editor.classList.add('code-editor__textarea');
        this._editor.style.flex = '1';
        this._editor.style.borderRadius = '5px';
        this._editor.style.border = '1px solid #ccc';
        this._editor.style.outline = 'none';
        this._editor.style.fontSize = '14px';
        this._editor.style.fontFamily = 'monospace';
        this._editor.style.padding = '10px';
        this._editor.style.resize = 'none';

        // if data is present, set the code
        if (this.data.code) {
            this._editor.value = this.data.code;
        }

        // append to element
        this._element.appendChild(this.languageSelector);
        this._element.appendChild(this._editor);

        return this._element;
    }

    save(blockContent) {
        return {
            language: this.languageSelector.value,
            code: this._editor.value
        };
    }

    validate(savedData) {
        if (!savedData.code.trim()) {
            return false;
        }

        return true;
    }

    renderSettings() {
        const wrapper = document.createElement('div');

        // language selector
        this.languageSelector = document.createElement('select');
        this.languageSelector.classList.add('language-selector');
        this.languageSelector.style.marginBottom = '10px';
        this.languageSelector.style.padding = '5px';
        this.languageSelector.style.borderRadius = '5px';
        this.languageSelector.style.border = '1px solid #ccc';
        this.languageSelector.style.outline = 'none';
        this.languageSelector.style.fontSize = '14px';
        this.languageSelector.style.fontFamily = 'monospace';
        this.languageSelector.style.width = '100px';

        let option;
        let textOption;
        // add languages
        supportedLanguages.map(language => {
            option = document.createElement('option');
            option.setAttribute('value', language);
            textOption = document.createTextNode(language);
            option.appendChild(textOption);
            this.languageSelector.appendChild(option);
        })

        wrapper.appendChild(this.languageSelector);

        return wrapper;
    }
}

const supportedLanguages = [
    "plain",
    "plaintext",
    "text",
    "txt",
    "extend",
    "insertBefore",
    "markup",
    "html",
    "mathml",
    "svg",
    "xml",
    "ssml",
    "atom",
    "rss",
    "css",
    "clike",
    "javascript",
    "js",
    "antlr4",
    "g4",
    "c",
    "csharp",
    "cs",
    "dotnet",
    "cpp",
    "go",
    "java",
    "json",
    "webmanifest",
    "json5",
    "jsonp",
    "markdown",
    "md",
    "powershell",
    "python",
    "py",
    "jsx",
    "typescript",
    "ts",
    "tsx",
    "regex",
    "ruby",
    "rb",
    "rust",
    "sass",
    "scss",
    "solidity",
    "sol",
    "sql"
]