Re-render Component on Canvas when tagName has changed
Question
I'm trying to build a basic Header component that lets you select H1 to H6 with a trait. But when an option is selected, the canvas doesn't update. The change is visible in the code view, and if I move the element in the canvas with the drag tool, the tag then changes. I have been reading the API docs as well as the source, but I can't make the component automatically re-render. I suspect that Grapes is not listening for a change of the component tag name. What is the appropriate way to force a re-render in this case?
var comps = editor.DomComponents;
var blocks = editor.BlockManager;
var textType = comps.getType('text');
var textModel = textType.model;
var textView = textType.view;
comps.addType('header', {
model: textModel.extend({
defaults: Object.assign({}, textModel.prototype.defaults, {
'custom-name': 'Header',
tagName: 'h1',
traits: [
{
type: 'select',
options: [
{value: 'h1', name: 'One (largest)'},
{value: 'h2', name: 'Two '},
{value: 'h3', name: 'Three '},
{value: 'h4', name: 'Four '},
{value: 'h5', name: 'Five '},
{value: 'h6', name: 'Six (smallest)'},
],
label: 'Size',
name: 'header-size',
changeProp: 1
}
]
}),
init() {
this.listenTo(this, 'change:header-size', this.changeTagName);
},
changeTagName() {
// view.tagName is a fn that returns model.tagName
this.set('tagName', this.get('header-size'));
}
}, {
isComponent: function(el) {
if(el && ['H1','H2','H3','H4','H5','H6'].includes(el.tagName)) {
return {type: 'header'};
}
}
}),
view: textView
});
blocks.add('header', {
label: 'Header',
category: 'Basic',
attributes: {class:'fa fa-header'},
content: {
type:'header',
content:'Insert your header text here',
activeOnRender: 1
}
});
Answers (3)
@z1lk I already added such a thing for the next release
// Model
// inside init
this.listenTo(this, 'change:tagName', this.tagUpdated);
// ...
tagUpdated() {
const coll = this.collection;
const at = coll.indexOf(this);
coll.remove(this);
coll.add(this, { at });
},
I'm not sure why el would be a string, but see the commit that closed the issue: https://github.com/artf/grapesjs/commit/e450cb98855d16ad819f1214350825a50e45e910
If you're using the latest Grapes version, the Component listens for a change of tagName and does the node replacement itself. So you should be able to remove your init and tagUpdated functions. The trait will update tagName and the Component will do the rest.
Edit:
Another thing I thought of is: sometimes the object passed to isComponent doesn't have the method that I call on it, and there will be an error thrown in that case. You could do a safety check first:
if(el && el.tagName && ['H1','H2','H3','H4','H5','H6'].includes(el.tagName)) {
...
Yeah this is because you can't change the tag name of an existing DOM element. Probably the solution would be, on tagName change, remove and replace the node (at the same position)
Related Questions and Answers
Continue research with similar issue discussions.
Issue #1511
[QUESTION] Change the html content of the selected component
I am trying to replace the html of the basic Text componet using the below code const component = editor.getSelected(); component.set('cont...
Issue #686
Trait view doesn't update input element when target value changes
If the target value (i.e. Component attribute/prop) is set manually and not via the trait input element, the input doesn't reflect that cha...
Issue #796
Can't drag component into canvas after styled element is cloned
Go to any of the demo, select a text box, give it a background color. Clone it. Then try to drag in another text component and it doesn't l...
Issue #1198
QUESTIONS : Find element in Model
I have custom component and it render below html, I want to update value of h4 tilte and other element on trait changed, but not sure how c...
Paid Plugins That Match This Issue
Curated by issue keywords and label relevance to help you ship faster.
Loading paid plugin recommendations...
Browse Plugin Categories
Jump directly to plugin category pages on the marketplace.