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.4k stars 4.06k forks source link

QUESTION: how to make textnode editing update component content? #3279

Closed abulka closed 3 years ago

abulka commented 3 years ago

I'm building a custom textarea component and want it to behave like the built in text component such that editing the textnode on the grapesjs canvas updates the textnode found in .components. And I want the component exported as HTML correctly e.g. <textarea>MY user edited TEXTNODE CONTENT</textarea>.

At the moment, the exported html of fancyTextarea always stays the same re the textnode, even though I edit it on the canvas. Is there an textnode change event I should be capturing and acting on - I can't find one? Here is my component

const fancyTextarea = editor => {
  editor.DomComponents.addType('fancyTextarea', {
    // extend: "??",
    isComponent: el => el.tagName == 'TEXTAREA',
    model: {
      defaults: {
        tagName: 'textarea',
        traits: [
          ...['id', 'name'],
          ...['rows', 'cols'], // why attrs emitted when empty?
        ],
        attributes: {
          name: 'yy',
        },
        components: [
        {
          type: 'textnode',
          content: ' * (component) textnode content',
          editable: false, // changes prop ok but can still edit?
        }
        ],
      },
    }
  })

  editor.BlockManager.add('idFancyTextarea', {
    label: 'Fancy Textarea',
    content: {
      type: 'fancyTextarea', // type name not appearing in style manager 
      classes: ['expand'],   //   if you define a style class?
      content: '* (block) textnode content', // textnode within textarea tag
    },
  });
}

const editor = grapesjs.init({
  container: '#gjs',
  fromElement: 1,
  height: '100%',
  storageManager: { type: 0 },
  style: '.expand {color: green; vertical-align: top; width: 100%; height: 100%;}',
  plugins: ['gjs-blocks-basic', fancyTextarea]
});

fiddle https://jsfiddle.net/tcab/q36ytzxd/

P.S. The closest I've come is to programmatically changing a textnode is

const node = component.findType('textnode')
node[0].set({content: 'ok I have altered you'})
//editor.render()   // results in a crash.

but whilst the component is updated and export is correct, the rendering on the canvas remains the same.

artf commented 3 years ago

Hi @abulka, as the editing is happening in the view, you should update the component model once the view is updated. So it should work with something like this

model: {
 ...
},
view: {
  events: {
    input: 'handleInputUpdate',
  },
  handleInputUpdate(ev) {
    this.model.components(ev.target.value);
  }
},