Skip to content

Commit 27bc4a7

Browse files
committed
[Autocomplete] Attempting a simpler "reset" of items
1 parent 83e5184 commit 27bc4a7

File tree

4 files changed

+71
-2
lines changed

4 files changed

+71
-2
lines changed

assets/dist/live_controller.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1264,6 +1264,13 @@ function executeMorphdom(rootFromElement, rootToElement, modifiedFieldElements,
12641264
fromEl.removeAttribute('parent-live-id-changed');
12651265
return true;
12661266
}
1267+
if (fromEl.hasAttribute('data-skip-morph')) {
1268+
fromEl.innerHTML = toEl.innerHTML;
1269+
return true;
1270+
}
1271+
if (fromEl.parentElement && fromEl.parentElement.hasAttribute('data-skip-morph')) {
1272+
return false;
1273+
}
12671274
return !fromEl.hasAttribute('data-live-ignore');
12681275
},
12691276
beforeNodeRemoved(node) {

assets/src/morphdom.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,11 +112,21 @@ export function executeMorphdom(
112112
return true;
113113
}
114114

115+
if (fromEl.hasAttribute('data-skip-morph')) {
116+
fromEl.innerHTML = toEl.innerHTML;
117+
118+
return true;
119+
}
120+
121+
if (fromEl.parentElement && fromEl.parentElement.hasAttribute('data-skip-morph')) {
122+
return false;
123+
}
124+
115125
// look for data-live-ignore, and don't update
116126
return !fromEl.hasAttribute('data-live-ignore');
117127
},
118128

119-
beforeNodeRemoved(node) {
129+
beforeNodeRemoved(node: Node) {
120130
if (!(node instanceof HTMLElement)) {
121131
// text element
122132
return true;

assets/test/controller/render.test.ts

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
'use strict';
1111

1212
import { shutdownTests, createTest, initComponent } from '../tools';
13-
import { getByText, waitFor } from '@testing-library/dom';
13+
import { getByTestId, getByText, waitFor } from '@testing-library/dom';
1414
import userEvent from '@testing-library/user-event';
1515
import { htmlToElement } from '../../src/dom_utils';
1616

@@ -208,6 +208,41 @@ describe('LiveController rendering Tests', () => {
208208
expect(ignoreElement?.outerHTML).toEqual('<div data-live-ignore="">Inside Ignore Name: <span>Kevin</span></div>');
209209
});
210210

211+
it('overwrites HTML instead of morph with data-skip-morph', async () => {
212+
const test = await createTest({ firstName: 'Ryan' }, (data: any) => `
213+
<div ${initComponent(data)}>
214+
<div data-skip-morph data-name="${data.firstName}">Inside Skip Name: <span data-testid="inside-skip-morph">${data.firstName}</span></div>
215+
216+
Outside Skip Name: ${data.firstName}
217+
218+
<button data-action="live#$render">Reload</button>
219+
</div>
220+
`);
221+
222+
const spanBefore = getByTestId(test.element, 'inside-skip-morph');
223+
expect(spanBefore).toHaveTextContent('Ryan');
224+
225+
test.expectsAjaxCall()
226+
.serverWillChangeProps((data: any) => {
227+
// change the data on the server so the template renders differently
228+
data.firstName = 'Kevin';
229+
});
230+
231+
getByText(test.element, 'Reload').click();
232+
233+
await waitFor(() => expect(test.element).toHaveTextContent('Outside Skip Name: Kevin'));
234+
// make sure the outer element is still updated
235+
const skipElement = test.element.querySelector('div[data-skip-morph]');
236+
if (!(skipElement instanceof HTMLElement)) {
237+
throw new Error('skipElement is not an HTMLElement');
238+
}
239+
expect(skipElement.dataset.name).toEqual('Kevin');
240+
const spanAfter = getByTestId(test.element, 'inside-skip-morph');
241+
expect(spanAfter).toHaveTextContent('Kevin');
242+
// but it is not just a mutation of the original element
243+
expect(spanAfter).not.toBe(spanBefore);
244+
});
245+
211246
it('cancels a re-render if the page is navigating away', async () => {
212247
const test = await createTest({greeting: 'aloha!'}, (data: any) => `
213248
<div ${initComponent(data)}>${data.greeting}</div>

doc/index.rst

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3243,6 +3243,23 @@ an element, that changes is preserved (see :ref:`smart-rerender-algorithm`).
32433243
``data-live-id`` attribute. During a re-render, if this value changes, all
32443244
of the children of the element will be re-rendered, even those with ``data-live-ignore``.
32453245

3246+
Overwrite HTML Instead of Morphing
3247+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3248+
3249+
Normally, when a component re-renders, the new HTML is "morphed" onto the existing
3250+
elements on the page. In some rare cases, you may want to simply overwrite the existing
3251+
inner HTML of an element with the new HTML instead of morphing it. This can be done by adding a
3252+
``data-skip-morph`` attribute:
3253+
3254+
.. code-block:: html
3255+
3256+
<select data-skip-morph>
3257+
<option>...</option>
3258+
</select>
3259+
3260+
In this case, any changes to the ``<select>`` element attributes will still be
3261+
"morphed" onto the existing element, but the inner HTML will be overwritten.
3262+
32463263
Define another route for your Component
32473264
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
32483265

0 commit comments

Comments
 (0)