formio / formio.js

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

Component reverts to its original schema on form change when using "event" type logic to trigger the action. #5617

Open ACmaster7 opened 1 month ago

ACmaster7 commented 1 month ago

Describe the bug If you set a trigger type of "event" in the component setting's logic tab and set the action type to "merge component schema" and for example set the action logic to something like this: schema = {label: "Updated Label"} It successfully updated the label of the component to "Updated Label" when that specific event is fired, but after that, as soon as you interact with the form (type in a text field, check a checkbox, etc..) the component's label or should I say "schema" reverts back to its original values. This is not the case when the trigger type is set to "simple".

Version/Branch 4.19.2

To Reproduce Steps to reproduce the behavior:

This is just an example, it results in the same bug in every component.

  1. Create a text field component and a button component and a number component
  2. Set the button's action to event, and give the event a name
  3. Open the text field component's setting, under the logic tab, set the trigger type to event and enter the event name you gave to the button
  4. Then set the action type to merge component schema and type: schema = {label: 'updated'}
  5. Use the form, and press the button to fire the event, you will see the text fields' label will change to "update"
  6. Now start typing in the number component you created in the beginning and you will see as soon as you type the text field's label will revert back to what it was before.

Expected behavior I expected the component's schema to change to the updated schema after the event trigger and remain the same, not to revert back to what it was before.

Potential Fix I narrowed the problem down myself to the attachLogic method, where after it checks if the component has changed, it will assign newComponent to this.component

attachLogic() {
    // Do not attach logic during builder mode.
    if (this.builderMode) {
      return;
    }

    this.logic.forEach(logic => {
      if (logic.trigger.type === 'event') {
        const event = this.interpolate(logic.trigger.event);

        this.on(
          event,
          (...args) => {
            const newComponent = fastCloneDeep(this.originalComponent);
            if (this.applyActions(newComponent, logic.actions, args)) {
              // If component definition changed, replace it.
              if (!_.isEqual(this.component, newComponent)) {
                this.component = newComponent;
                const visible = this.conditionallyVisible(null, null);
                const disabled = this.shouldDisabled;
                // ..........

I added this line as well and it seems to have fixed the problem: this.originalComponent = newComponent;

But I have no idea how to fork a library and change the code and stuff, I needed this functionality for the selectBox componnet to generate checkboxes based on some data on the form, and I just overrode the method in the SelectBox component

jeriah-formio commented 2 weeks ago

FIO-8479