Issue #1162Opened June 4, 2018by kaloyankostov0 reactions

[Question]: Editable components in Handlebars rendered template

Question

Hi, I've been using grapes for about a couple of days now. Thanks for the awesome work on this project. I've read through the API docs (hopefully didn't miss this piece) and I've also tried some stuff out. Basically, I'm using grapes to load existing .hbs (handlebars) files in that the user will then be able to edit. I saw a previous question regarding how to integrate handlebars in #938 and I followed the advice there and ended up with.

   var comps = this.grapesEditor.DomComponents;

    // Get the model and the view from the default Component type
    var defaultType = comps.getType('default');
    var defaultModel = defaultType.model;
    var defaultView = defaultType.view;

    comps.addType('handlebars', {
        model: defaultModel.extend({
              defaults: Object.assign({}, defaultModel.prototype.defaults, {
                droppable: true,
                editable: true
              })
            }),
      view: defaultType.view.extend({
        // The render() should return 'this'
        render: function () {
          // Extend the original render method
          defaultType.view.prototype.render.apply(this, arguments);
          const template = Handlebars.compile(this.el.innerHTML);
          this.el.innerHTML = template();
          return this
        },
      }),
    });

And then setting the components on the editor like so:

      this.grapesEditor.setComponents({
        type: 'handlebars',
        content: fileData
      });

This works very well and I end up with my rendered handlebars template being shown in the editor with the source html remaining as handlebars template which is exactly what I need. However when the template gets brought in, it comes in as a single component in the layer manager called Handlebars, meaning I cannot edit individual elements or add anything new.

image

This makes perfect sense when reading the docs and considering that components are just atomic pieces that comprise building blocks. That being said, i'm not sure how to go about making it so that

  • I can bring in an existing snippet of handlebars code
  • Render the handlebars template in the edtior
  • Keep the source code of the handlebars template
  • Have the individual elements of the rendered handlebars template be editable in the grapes editor

I see that passing the uncompiled handlebars HTML string directly to editor.setComponents() does work in getting me editable components but obviously doesn't give me a rendered handlebars template. On the other hand, passing the compiled handlebars HTML template string in the same way to editor.setComponents() does work in giving me individually editable components from the compiled handlebars template, but changes the source html (to the compiled html).

I will continue to investigate and read through some samples / trying some things out, but I'm curious if its possible to do this with a custom component somehow.

Answers (3)

kaloyankostovJune 6, 20180 reactions

Just to clarify further as I now feel that my post was longer than it needed to be. I did some more digging and found #978. The issue described there is identical to mine. I basically have a custom component which has several child elements in the html string however none of the children are selectable/editable. They all get brought in as one single editable element on the parent element (most often a <div> in my case). Is it possible to iterate through all the children and make them individually recognized components just like when using editor.setComponents() but instead by using a custom component? I need a custom component because I would like to change the rendered view to be different from the source html. Thanks

artfJune 16, 20180 reactions

I see there are some conflicts in few points:

  • Keep the source code of the handlebars template
  • Have the individual elements of the rendered handlebars template be editable in the grapes editor

If you edit stuff you'd expect to get those edits, right? But you're still asking handlebars template as a return, so which is the point of editing them??

BTW I'll give you few hints, then try to figure it out what do you need (didn't test it):

comps.addType('handlebars', {
      model: defaultModel.extend({
              defaults: {
				...defaultModel.prototype.defaults
                droppable: true,
                editable: true
              },
			  init() {
				// If I have no components inside, I compile the template
			    // and it will be an editable content
				if (!this.components().length) {
					this.components(Handlebars.compile(this.get('template')));
				}
			  },
			  toHTML() {
				// If I have components I'll follow the original method
				// otherwise return the template
				if (this.components().length) {
					return defaultModel.prototype.toHTML.apply(this, arguments);
				} else {
					return this.get('template');
				}
			  }
      }, {
			// isComponent is mandatory when you define new components
			isComponent(el) {
				// Accept it only when `handlebars` type is explicitly requested
				return false;
			}
	  }),
      view: defaultType.view
    });

Then add a block like this

editor.BlockManager.add('hdb1', {
	label: 'Template 1',
	content: {
		type: 'handlebars',
		template: '<div ...>...</div>', // you Handlebars template
	}
})
no-response[bot]June 26, 20180 reactions

This issue has been automatically closed because there has been no response to our request for more information from the original author. With only the information that is currently in the issue, we don't have enough information to take action. Please reach out if you have or find the answers we need so that we can investigate further.

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.