GrapesJS / grapesjs

Free and Open source Web Builder Framework. Next generation tool for building templates without coding
https://grapesjs.com
BSD 3-Clause "New" or "Revised" License
22.37k stars 4.05k forks source link

BUG: this.on('change:attributes:type', this.handleTypeChange) do not support array type #4851

Closed chaegumi closed 1 year ago

chaegumi commented 1 year ago

GrapesJS version

What browser are you using?

Chrome 108.0.5359.125

Reproducible demo link

https://codesandbox.io/s/frosty-darkness-7po7xl

Describe the bug

How to reproduce the bug?

  1. use myBlock
  2. click test button

What is the expected behavior? this.on("change:list1", this.handleList1Change);
work every time

What is the current behavior? this.on("change:list1", this.handleList1Change); only run once

If is necessary to execute some code in order to reproduce the bug, paste it here below:

import grapesjs from "grapesjs";

const myPlugin = function (editor, opts) {
  editor.TraitManager.addType("listitem", {
    createInput({ trait }) {
      this.traitName = trait.get("name");
      this.items = [
        {
          id: 1,
          title: "Item1"
        }
      ];
      const el = document.createElement("div");

      el.innerHTML = '<button type="button">test</button>';

      el.querySelector("button").addEventListener("click", (ev) =>
        this.onChange(ev)
      );

      return el;
    },
    onEvent({ elInput, component, event }) {
      // console.log(event);

      const itemLength = this.items.length;

      this.items.push({
        id: itemLength,
        title: `Item${itemLength}`
      });

      component.set(this.traitName, this.items);
      console.log("onEvent", this.items);
    },
    onUpdate({ elInput, component }) {}
  });

  editor.DomComponents.addType("myComponent", {
    isComponent: (el) => {
      if (el && el.classList && el.classList.contains("widget1")) {
        return true;
      }
    },
    model: {
      defaults: {
        attributes: { class: "widget1" },
        components: `<div>test</div>`,
        traits: [
          {
            type: "listitem",
            name: "list1",
            label: "list1",
            changeProp: 1
          }
        ]
      },
      init() {
        this.on("change:list1", this.handleList1Change);
      },
      handleList1Change() {
        console.log("onChange", this.attributes.list1);
      }
    },
    view: {}
  });

  editor.BlockManager.add("myBlock", {
    label: "MyBlock",
    content: { type: "myComponent" },
    select: true
  });
};

const editor = grapesjs.init({
  container: "#gjs",
  fromElement: 1,
  storageManager: { type: 0 },
  plugins: [myPlugin]
});

editor.on("component:selected", function (component) {
  editor.Panels.getButton("views", "open-tm").set({ active: true });
});

image

Code of Conduct

artf commented 1 year ago

Listeners don't see deep changes so you have to create a new array in that case

component.set(this.traitName, [...this.items]);
chaegumi commented 1 year ago

Thanks @artf. I use JSON.stringify and JSON.parse to deal my data.