formio / formio.js

JavaScript powered Forms with JSON Form Builder
https://formio.github.io/formio.js
MIT License
1.86k stars 1.06k forks source link

Feature: Enable Autocomplete with Language tools for Ace editor #3464

Open besmiralia opened 3 years ago

besmiralia commented 3 years ago

I am trying to introduce autocomplete from components when using javascript code in customDefaultValue and calculatedValue. I noticed ace editor has an autocomplete functionality which can be enabled by including the script ext-language_tools.js and activating it with. editor.require('ace/ext/language_tools');

below is the snippet from Component.js >addAce

addAce(element, settings, onChange) {
...
    settings = _.merge(settings, {
      enableBasicAutocompletion: true,
      enableSnippets: true,
      enableLiveAutocompletion: true
    });
    settings = _.merge(this.wysiwygDefault.ace, _.get(this.options, 'editors.ace.settings', {}), settings || {});
    return Formio.requireLibrary('ace', 'ace', _.get(this.options, 'editors.ace.src', ACE_URL), true)
      .then((editor) => {
        editor.require('ace/ext/language_tools');
        editor = aceLib.edit(element);
        editor.removeAllListeners('change');
...

I tried changing the ACE_URL to an array which includes both scripts but it looks like the tools script loads before the main ace script and it throws errors.

I am having some trouble including and activating the script above. If you can guide me on that, I can later make it a pull request to include the new feature.

travist commented 3 years ago

Try adding this to your own application.

const addAce = Formio.Components.components.component.addAce;
Formio.Components.components.component.addAce = function(element, settings, onChange) {
  return addAce.call(this, element, settings, onChange).then(function(editor) {
    editor.require('ace/ext/language_tools');
    return editor;
  });
};
besmiralia commented 3 years ago

Thank you @travist I will try this today and let you know

besmiralia commented 3 years ago

Hi @travist I tested the above in the following fiddle. https://jsfiddle.net/8whur5o0/1/ It seems like addAce from the first line returns undefined

travist commented 3 years ago

Forgot the prototype

const addAce = Formio.Components.components.component.prototype.addAce;
Formio.Components.components.component.prototype.addAce = function(element, settings, onChange) {
  return addAce.call(this, element, settings, onChange).then(function(editor) {
    editor.require('ace/ext/language_tools');
    return editor;
  });
};
besmiralia commented 3 years ago

Thank you @travist This seems to be working

https://jsfiddle.net/8whur5o0/3/

besmiralia commented 3 years ago

Hi @travist This is an updated fiddle https://jsfiddle.net/8whur5o0/5/ with more components in the form and autocomplete pulling data from its components. It still seems to be some timing issue because sometimes it works sometimes it throws the error below which I believe is due to including both scripts (main ace.js + language tools.js) and the second one (language-tools) being resolved first.

ext-language_tools.js:1 Uncaught ReferenceError: define is not defined
    at ext-language_tools.js:1
travist commented 3 years ago

Try including the ACE editor in the DOM before you load the Form.io renderer. The way our renderer works is it first looks in the global context for a library, in this case it looks for "window.ace" and if that exists, it will NOT lazy load the library. This will ensure that the library is included before Form.io is executed. You may also be able to add your plugins at that moment as well.

jeanslegel commented 1 year ago

Hi @travist This is an updated fiddle https://jsfiddle.net/8whur5o0/5/ with more components in the form and autocomplete pulling data from its components. It still seems to be some timing issue because sometimes it works sometimes it throws the error below which I believe is due to including both scripts (main ace.js + language tools.js) and the second one (language-tools) being resolved first.

ext-language_tools.js:1 Uncaught ReferenceError: define is not defined
    at ext-language_tools.js:1

hello @besmiralia , I'm trying to do the same thing that you were trying to do (but I'm using react). Did you manage to succeed ?