Issue #2639Opened March 12, 2020by MiseryMachine0 reactions

[QUESTION]: GrapesJS moving Mustache tokens

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, 20200 reactions

@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, 20200 reactions

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, 20200 reactions

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...

Browse Plugin Categories

Jump directly to plugin category pages on the marketplace.