Issue #1632✓ SolvedOpened December 5, 2018by cnaa975 reactions

Control table cell (add row, column..)

快速解答by shubhd473

Hey, @cnaa97 No worries I have added the default commands in the toolbar. I got what I wanted. Thanks for helping. Below is the code

Read full answer below ↓

Question

Hello. I want to dev some of feature to control the table.

There are many feature for table the other editor like add columns, rows, set color, reset column width for each cell...

I just have a dev plan to implementation on below..

1. add a button on block manager

bm.add('table-block', {
  id: 'table',
  label: 'Table',
  category: 'Basic',
  attributes: { class: 'fa fa-table' },
  content: `
      <table class="table table-striped table-bordered table-resizable">
          <tr><td></td><td></td><td></td></tr>
          <tr><td></td><td></td><td></td></tr>
          <tr><td></td><td></td><td></td></tr>
      </table>
    `,
});

this is a dummy table 3x3. each cell have a text component.

2018-12-05 17-11-35 2018-12-05 17_12_04

2. customize toolbar on cell

{
    defaults: {
      ...Component.prototype.defaults,
      type: 'cell',
      tagName: 'td',
      draggable: ['tr'],
      toolbar: [
        {
          attributes: { class: "fa fa-arrows" },
          command: "tlb-move"
        },
        {
          attributes: { class: "fa fa-flag" },
          command: "table-insert-row-above"
        }
      ]
    },
  },

add a custom command to insert row above.

3. Add a command in order to insert a row

run(editor, sender, opts) {
  var domComponents = editor.DomComponents;

  domComponents.addComponent({
      tagName: 'table',
      removable: true, // Can't remove it
      draggable: true, // Can't move it
      copyable: true, // Disable copy/past
      style: { background: 'red'},
      attributes: { title: 'here' },
      content: `<tr data-gjs-type="row" data-highlightable="1">
         <td data-gjs-type="cell" data-highlightable="1" style="min-width: 100px;"><div data-gjs-type="text" data-highlightable="1"></div></td>
    });
}

2018-12-05 17-14-10 2018-12-05 17_16_29

But the problem is...

  1. Cannot detect the cell's location. above code just add on canvas below. not inside cell.
  2. Cannot add multiple components into the cell. It just added only one depth. but need to add muitiple depth. (tr > td * 3)

Anyone have a nice idea? I cannot find a awesome plugin.

Have a nice day.

Answers (3)

👍 Most helpfulshubhd47October 7, 2019

Hey, @cnaa97 No worries I have added the default commands in the toolbar. I got what I wanted. Thanks for helping.

Below is the code

        const blockManager = this._editor.BlockManager;
        blockManager.add('table-block', {
          id: 'table',
          label: 'Table',
          category: 'Basic',
          attributes: { class: 'fa fa-table' },
          content: `
              <table class="table  table-bordered table-resizable">
                  <tr><td></td><td></td><td></td></tr>
                  <tr><td></td><td></td><td></td></tr>
                  <tr><td></td><td></td><td></td></tr>
              </table>
            `,
        });
        const TOOLBAR_CELL = [
          {
            attributes: { class: "fa fa-arrows" },
            command: "tlb-move"
          },
          {
            attributes: { class: "fa fa-flag" },
            command: "table-insert-row-above"
          },
          
          {
            attributes: {class: 'fa fa-clone'},
            command: 'tlb-clone',
          },
          {
            attributes: {class: 'fa fa-trash-o'},
            command: 'tlb-delete',
          }
        ];
        const getCellToolbar = () => TOOLBAR_CELL;


        const components = this._editor.DomComponents;
        const text = components.getType('text');
        components.addType('cell', {
          model: text.model.extend({
            defaults: Object.assign({}, text.model.prototype.defaults, {
              type: 'cell',
              tagName: 'td',
              draggable: ['tr'],
              
            }),
          },

            {
              isComponent(el) {
                let result;
                const tag = el.tagName;
                if (tag == 'TD' || tag == 'TH') {
                  result = {
                    type: 'cell',
                    tagName: tag.toLowerCase()
                  };
                }
                return result;
              }
            }),
          view: text.view,
        });

        

        this._editor.on('component:selected', m => {
          const compType = m.get('type');
          switch (compType) {
            case 'cell':
              m.set('toolbar', getCellToolbar()); // set a toolbars
          }
        });



        this._editor.Commands.add('table-insert-row-above', editor => {
          const selected = editor.getSelected();

          if (selected.is('cell')) {
            const rowComponent = selected.parent();
            const rowIndex = rowComponent.collection.indexOf(rowComponent);
            const cells = rowComponent.components().length;
            const rowContainer = rowComponent.parent();

            rowContainer.components().add({
              type: 'row',
              components: [...Array(cells).keys()].map(i => ({
                type: 'cell',
                content: 'New Cell',
              }))
            }, { at: rowIndex });
          }
        });
artfDecember 7, 2018
  1. The content inside the component definition is for static text (eg. the content is used for editing with Rich Text Editor) so you can't select its element once added, instead you should use components: '<tr data-gjs-type="row" ...'
  2. You can always get the selected Component and use its API, so your table-insert-row-above could be:
editor.Commands.add('table-insert-row-above', editor => {
  const selected = editor.getSelected();

  if (selected.is('cell')) {
      const rowComponent = selected.parent();
      const rowIndex = rowComponent.collection.indexOf(rowComponent);
      const cells = rowComponent.components().length;
      const rowContainer = rowComponent.parent();

      rowContainer.components().add({
        type: 'row',
        components: [ ...Array(cells).keys() ].map(i => ({
          type: 'cell',
          content: 'New Cell',
        }))
      }, { at: rowIndex });
  }
});
cnaa97December 10, 2018

Thanks for your kindness answer.

Related Questions and Answers

Continue research with similar issue discussions.

Paid Plugins That Match This Issue

Curated by issue keywords and label relevance to help you ship faster.

View all plugins

Loading paid plugin recommendations...

Free option

Check the open-source GrapesJS plugins on GitHub or run a quick search in our free catalog.

Browse free plugins →
Premium option

Premium plugins ship with support, regular updates, and production-ready features — save days of integration work.

Browse premium plugins →

Browse Plugin Categories

Jump directly to plugin category pages on the marketplace.