Issue #2639💬 AnsweredOpened March 12, 2020by MiseryMachine0 reactions

GrapesJS moving Mustache tokens

快速解答by pouyamiralayi

@MiseryMachine have you tried wrapping your table internal's inside a `tbody` in your block definition? or at least moving your mustache tokens inside a tag?

Read full answer below ↓

Question

Hello, I am working with GrapesJS to allow users to create report templates. I've run into a problem with a block that creates a table, but the table rows are determined by Mustache tokens. However, when rendered, the tokens are moved outside of the table element. I believe the table or table row style is not allowing the existence of these tokens within the table element structure.

My block:

    bm.add('product-list-block', {
        label: 'Product List',
        attributes: {
            class: 'fa fa-header'
        },
        category: 'Products',
        content: `
            <div>
                <table data-gjs-type="product-list-type" style="width: 100%; margin: 10px 15px;">
                    <tr style="height: 24px; background: #72a1c3">
                        <th style="width: 15%">Image</th>
                        <th>Details</th>
                    </tr>
                    {{#bomGroupProducts}}
                    <tr>
                        <td style="width: 15%">{{productImageUrl}}</td>
                        <td>
                            <div style="font-weight: bold">{{productName}}</div>
                            <div>{{productDescription}}</div>
                            <div>SKU: {{productSku}}</div>
                        </td>
                    </tr>
                    {{/bomGroupProducts}}
                </table>
            </div>`
    });

The product-list-type:

    domc.addType('product-list-type', {
        extend: 'table',
        model: tableModel.extend({
            defaults: {
                ...defaultModel.prototype.defaults,
                // Default props
                draggable: true,
                droppable: true,
                attributes: {
                    title: productListTitle,
                    style: 'color: red; font-weight: bold;'
                }
            }
        }),
        isComponent: el => {
            // console.log(el);
            // console.log(el.tagName + '[title=' + el.title + ']');

            if (el.tagName === 'th' && el.getAttribute('data-gjs-type') === 'product-list-type') {
                return {
                    type: 'product-list-type'
                };
            }

            return '';
        }
    });

When I drop the element onto the canvas, the {{#bomGroupProducts}} and {{/bomGroupProducts}} tokens are moved above the entire table.

<div style="box-sizing: border-box;">
  {{#bomGroupProducts}}
  {{/bomGroupProducts}}
  <table title="productListTitle" id="i0x6" style="box-sizing: border-box; width: 100%; margin: 10px 15px;" width="100%">
    <thead style="box-sizing: border-box;">
      <tr id="icuj" style="box-sizing: border-box; height: 24px; background: #72a1c3;">
        <th id="izmb" style="box-sizing: border-box; width: 15%;">Image
        </th>
        <th style="box-sizing: border-box;">Details
        </th>
      </tr>
    </thead>
    <tbody style="box-sizing: border-box;">
      <tr style="box-sizing: border-box;">
        <td id="idbqf" style="box-sizing: border-box; width: 15%;" width="15%">{{productImageUrl}}
        </td>
        <td style="box-sizing: border-box;">
          <div id="iwb35" style="box-sizing: border-box; font-weight: bold;">{{productName}}
          </div>
          <div style="box-sizing: border-box;">{{productDescription}}
          </div>
          <div style="box-sizing: border-box;">SKU: {{productSku}}
          </div>
        </td>
      </tr>
    </tbody>
  </table>
</div>

I need those tokens around the <tr> elements, so that the Mustache generator creates rows for each product as needed. Is there a way in the style/component I can prevent this?

Thanks in adance, Randy

Answers (3)

pouyamiralayiMarch 12, 2020

@MiseryMachine have you tried wrapping your table internal's inside a tbody in your block definition? or at least moving your mustache tokens inside a tag?

MiseryMachineMarch 13, 2020

Thanks for your suggestion. I have tried that with the same result, unfortunately.

block script:

    bm.add('product-list-block', {
        label: 'Product List',
        attributes: {
            class: 'fa fa-header'
        },
        category: 'Products',
        content: `
            <div>
                <table data-gjs-type="product-list-type" style="width: 100%; margin: 10px 15px;">
                    <tr style="height: 24px; background: #72a1c3">
                        <th style="width: 15%">Image</th>
                        <th>Details</th>
                    </tr>
                    <tbody data-gjs-type="product-list-body-type">
                    {{#bomGroupProducts}}
                    <tr>
                        <td style="width: 15%">{{productImageUrl}}</td>
                        <td>
                            <div style="font-weight: bold">{{productName}}</div>
                            <div>{{productDescription}}</div>
                            <div>SKU: {{productSku}}</div>
                        </td>
                    </tr>
                    {{/bomGroupProducts}}
                    </tbody>
                </table>
            </div>`
    });

Output:

<div style="box-sizing: border-box;">
  {{#bomGroupProducts}}
  {{/bomGroupProducts}}
  <table title="productListTitle" id="ip2d" style="box-sizing: border-box; width: 100%; margin: 10px 15px;" width="100%">
    <tbody style="box-sizing: border-box;">
      <tr id="i5t5" style="box-sizing: border-box; height: 24px; background: #72a1c3;">
        <th id="iqme" style="box-sizing: border-box; width: 15%;">Image
        </th>
        <th style="box-sizing: border-box;">Details
        </th>
      </tr>
    </tbody>
    <tbody style="box-sizing: border-box;">
      <tr style="box-sizing: border-box;">
        <td id="i8w2m" style="box-sizing: border-box; width: 15%;" width="15%">{{productImageUrl}}
        </td>
        <td style="box-sizing: border-box;">
          <div id="ir6u9" style="box-sizing: border-box; font-weight: bold;">{{productName}}
          </div>
          <div style="box-sizing: border-box;">{{productDescription}}
          </div>
          <div style="box-sizing: border-box;">SKU: {{productSku}}
          </div>
        </td>
      </tr>
    </tbody>
  </table>
</div>

Maybe it's because GrapesJS is, by default, enforcing HTML structure. I'm still trying to work this out though.

artfMarch 18, 2020

No, you can't do that because in that case, you have an invalid HTML, so the HTML parser moves it out. You have to create a valid HTML content to make the browser render it correctly:

<tr>
	<td>
		{{#bomGroupProducts}}
			<table>
				...
                    <tr>
                        <td style="width: 15%">{{productImageUrl}}</td>
                        <td>
                            <div style="font-weight: bold">{{productName}}</div>
                            <div>{{productDescription}}</div>
                            <div>SKU: {{productSku}}</div>
                        </td>
                    </tr>
				...
			</table>
		{{/bomGroupProducts}}
	</td>
</tr>

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.