The morph operation performs fast, lightweight DOM diffing/patching without a virtual DOM. It compares the current DOM with new content and applies only the necessary changes.
Using children_only: true
When morphing with children_only: true, the provided html must follow these rules to succeed:
- It must have a single top-level container element with the same CSS selector as the target.
- Inside that container, there must be an element node, not a text node.
Example for collections:
If rendering a collection of partials, wrap the render in a container because the top-level container cannot exist inside each individual partial.
# Correct way to morph a collection
morph(
children_only: true,
selector: "#bar",
html: "<div id=\"bar\">" + render(Bar.all) + "</div>"
)
Customizing morph via Lifecycle Events
You can modify operation parameters in the cable-ready:before-morph event. The event.detail.content object provides a direct reference to the internal template element's content (a DocumentFragment).
Important: You cannot assign a new value to event.detail.content. Instead, mutate the children inside the content using standard DOM APIs:
document.addEventListener('cable-ready:before-morph', event => {
event.detail.content.querySelector('#foo').style.color = 'red'
})
Parameters:
selector (required): CSS selector or XPath expression.html: The HTML to use for morphing.children_only: (Optional) If true, only morphs child nodes, skipping the parent.permanent_attribute_name: (Optional) An attribute name (e.g., data-permanent) that prevents elements from being updated.batch, cancel, delay, focus_selector, select_all, xpath: (See standard operation options)
Lifecycle Events:
cable-ready:before-morphcable-ready:after-morph
morph(
selector: "#content",
html: "<div id='content'>New Content</div>",
permanent_attribute_name: "data-permanent"
)