Bad id created when using "no-update" and scoped id together
Marko Version: x.x.x
5.1.10
Details
If you use "no-update" on a scoped form element, the id of the element isn't correct. The following marko will generate an id of "s0-0-0-13-s0-0-0-13-input1"
<input id:scoped="input1" no-update />
I don't know if this is a huge issue other than the fact that if I use a "for" tag on a label, the for tag uses "s0-0-0-13-input1", so doesn't match.
Expected Behavior
The id should be s0-0-0-13-input1 or at least should be matched by the "for".
<label for:scoped="input1">Input</label>
<input id:scoped="input1" no-update />
should generate:
<label for="s0-0-0-13-input1">Input</label>
<input id="s0-0-0-13-input1">
Actual Behavior
<label for="s0-0-0-13-input1">Input</label>
<input id="s0-0-0-13-s0-0-0-13-input1">
Possible Fix
Additional Info
Your Environment
Node v14.15..4 Chrome v88 Desktop
Steps to Reproduce
<label for:scoped="input1">Input</label>
<input id:scoped="input1" no-update />
Stack Trace
I messed around with your repro case in Try Online, but could only conclude a few things:
-
The “Compiled (HTML)” looks like something is clearly goofy with nested
_component.elId’s:out.w( `<label${_marko_attr("for", _component.elId("input1"))}>Input</label>` ); // … out.w( `<input${_marko_attr( "id", _component.elId(_component.elId("input1")) )}>` );“Compiled (VDOM)” shows the same problem.
-
Adding
no-updateto the<label>makes the IDs match -
I can’t seem to chain
:scopedand:no-updateon the same attribute, so I can’t tell iffor:scoped:no-updatewould also make the IDs match
The issue is in copying the attributes inside no-update modifier: https://github.com/marko-js/marko/blob/ab1d038070e1eb23323d0b790e68489ade280c3e/packages/translator-default/src/tag/attribute/modifiers/no-update.js#L21
https://github.com/marko-js/marko/blob/ab1d038070e1eb23323d0b790e68489ade280c3e/packages/marko/src/runtime/vdom/preserve-attrs.js#L6
If the no-update modifier comes first than scoped attribute has correct value:
<label for:scoped="input1">Input</label>
<input no-update id:scoped="input1" />
I had the same issue, using id:scoped= and no-update directives creates a completely different id than expected.
My solution was using no-update-body instead of no-update, it worked for me for the elements I was using.
<h2
id:scoped="idString"
no-update-body
>
${state.initialState}
</h2>