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

[Question] Export dynamic section with config #305

Closed broncha closed 7 years ago

broncha commented 7 years ago

Hi. First of all, thank you for putting all your hard work on this. This definitely is a great library. I am thinking of integrating this as a layout manager for a product we have. Its like Shopify where you can customise the layout of the store. Now we can have many blocks and component which are rendered dynamically. For example, we can have a block that shows few cards with products from a specific category. We use a twig file to render that particular block. All that the block needs to know is the category its rendering the product from, and the HTML is generated dynamically.

How would I do this with the component in GrapeJS. I have gone through the component documentation and I cant seem to find a way to do this.

Heres what I have in mind,

  1. Create a component/block called "Product Block"
  2. That block would have some properties, that the user can set in the style manager. For example, the category from the list of categories.
  3. In the canvas, the block would be rendered with the HTML from AJAX request, which will contain the block parameters.

So far so good. Now I need this information to be saved, so in the live site, the block is rendered properly. I don't know the workflow of the GrapeJS internally. But is there a way, that the block could be represented by a twig block (we use twig templating), or some shortcode (like in WordPress), in the final output of the canvas, but the canvas itself shows the evaluated version of that placeholder?

Cheers

broncha commented 7 years ago

Hi, I think I am getting a hold of this now. I made a custom component for product list, which has a trait for the category. I can select the category from the dropdown in the panel. Thats great. But I dont want the components inside the product list (like images, text etc) to be editable. How do I do this? The entire component is generated dynamically, and the user should only be able to add/remove the entire component, not child components

artf commented 7 years ago

Hi @broncha you can update Component properties by using data-gjs-* attributes, so, for example, in your case you might want to add this to your child components

<div data-gjs-removable="false" data-gjs-draggable="false" data-gjs-copyable="false" ...></div>
...
broncha commented 7 years ago

Hi @artf, thanks! I figured that out. Now this is what I have

<div data-gjs-type="categoryList" data-gjs-editable="false" data-gjs-draggable=".container-fluid"> 
<h2 data-gjs-editable="false" data-gjs-badgable="false" data-gjs-removable="false" data-gjs-draggable="false" data-gjs-droppable="false" data-gjs-stylable="false" data-gjs-highlightable="false" data-gjs-copyable="false">Browse by Category</h2> 
<div class="row" data-gjs-editable="false" data-gjs-badgable="false" data-gjs-removable="false" data-gjs-draggable="false" data-gjs-droppable="false" data-gjs-stylable="false" data-gjs-highlightable="false" data-gjs-copyable="false"> 
<div class="col-xs-4 html-content-block" data-gjs-badgable="false" data-gjs-editable="false" data-gjs-removable="false" data-gjs-draggable="false" data-gjs-droppable="false" data-gjs-stylable="false" data-gjs-highlightable="false" data-gjs-copyable="false"> 
<div class="html-content-animation" data-gjs-badgable="false" data-gjs-editable="false" data-gjs-removable="false" data-gjs-draggable="false" data-gjs-droppable="false" data-gjs-stylable="false" data-gjs-highlightable="false" data-gjs-copyable="false"></div>
<a href="http://demo-shop.pasls.dev/category/sasd" data-gjs-badgable="false" data-gjs-editable="false" data-gjs-removable="false" data-gjs-draggable="false" data-gjs-droppable="false" data-gjs-stylable="false" data-gjs-highlightable="false" data-gjs-copyable="false"> <img data-gjs-editable="false" data-gjs-badgable="false" data-gjs-removable="false" data-gjs-draggable="false" data-gjs-droppable="false" data-gjs-stylable="false" data-gjs-highlightable="false" data-gjs-copyable="false" src="http://demo-shop.pasls.dev/media/cache/demo-shop/d_cat_thumb/u/59003a416d97a_category_top_4.jpg" alt="" class="img-responsive"> </a> 
</div>
<div class="col-xs-4 html-content-block" data-gjs-badgable="false" data-gjs-editable="false" data-gjs-removable="false" data-gjs-draggable="false" data-gjs-droppable="false" data-gjs-stylable="false" data-gjs-highlightable="false" data-gjs-copyable="false"> 
<div class="html-content-animation" data-gjs-badgable="false" data-gjs-editable="false" data-gjs-removable="false" data-gjs-draggable="false" data-gjs-droppable="false" data-gjs-stylable="false" data-gjs-highlightable="false" data-gjs-copyable="false"></div>
<a href="http://demo-shop.pasls.dev/category/shoes" data-gjs-badgable="false" data-gjs-editable="false" data-gjs-removable="false" data-gjs-draggable="false" data-gjs-droppable="false" data-gjs-stylable="false" data-gjs-highlightable="false" data-gjs-copyable="false"> <img data-gjs-editable="false" data-gjs-badgable="false" data-gjs-removable="false" data-gjs-draggable="false" data-gjs-droppable="false" data-gjs-stylable="false" data-gjs-highlightable="false" data-gjs-copyable="false" src="http://demo-shop.pasls.dev/media/cache/demo-shop/d_cat_thumb/u/5900419537180_category_top_4.jpg" alt="" class="img-responsive"> </a> 
</div>
</div>
<div class="vert-space-30" data-gjs-badgable="false" data-gjs-editable="false" data-gjs-removable="false" data-gjs-draggable="false" data-gjs-droppable="false" data-gjs-stylable="false" data-gjs-highlightable="false" data-gjs-copyable="false"></div>
</div>

Bear with me here. That is quite a lot duplicated attributes there. Its entire block, which is dynamically generated. I dont need any of the children to be editable or highlightable. Now I cannot select the component. I have disabled all properties in the children. The blue border still appears when I hover over the children.

How can I make it so that, clicking inside the Component (any of the children too) selects the component?

ezgif com-optimize

As you can see, I have to carefully hover over the empty space to select the entire component. And even when all the children are not editable, highlightable etc., they react to hover.

artf commented 7 years ago

Still didn't get which is your final goal but you can append your children as a static content, eg.

blockManager.add('some-block', {
    ...
    content: {
        type: 'your-custom-type',
        ...
        // This will parse, create and append models to the structure
        components: '<div...>...',
        // This will just add the content as a plain HTML, no models (therefore you can't select them)
        //  here you don't need model attributes
        content: '<div ..',
    }
})

but take into account that those elements, added via content, are not selectable but are may still blocking the pointer from selecting the parent, the solution is to add pointer-events: none to the container of your children

editor.DomComponents.addType('your-custom-type', {
     ...
     view: ... {
          ...
          render() {
            // ... call the parent render and other stuff
            // Make your content wrapped inside some container so it will be the firstChild
            this.el.firstChild.style.pointerEvents = 'none';
           }
    }
})
broncha commented 7 years ago

I think I got what I needed using

 <div data-gjs-..... style="pointer-events: none;" >

But the data attributes in all the child elements are still I think, redundant. This is a valid use case no? For builders who have widgets and all.

artf commented 7 years ago

@broncha if you use content you don't need any of those data attributes

broncha commented 7 years ago

@artf Thanks. Ill try that out. Could you help me with one last thing? How can i get a reference to the components added? I will not be storing the html, rather the json object that describes the component and the traits. Later the page will be generated from the json. For example, here in category list, i will have a trait, say number of categories to show. Now since the exact categories to show will be dynamic, i need to get the list of components/blocks added and their traits.

artf commented 7 years ago

You can get components via DomComponents  module

const dc = editor.domComponents;
const wrapper = dc.getWrapper();

// Iterate children
wrapper.get('components').each(component => {
     const traits = component.get('traits'); // trait collection
     traits.each(trait => ...);

    // go deeper
    component.get('components').each(....)    
})
lock[bot] commented 5 years ago

This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.