Form, app url, slice change events
Opened this issue · 8 comments
slice
is a section in element's dataset
tree. Its content is defined by element value where the slot
attribute is defined, a "hi" string in this sample:
<input slot="user-input" value="hi">
Elements with slice
attribute like local-storage
in current implementation on slice data change notifies the parent tree invoking parent.onSlice .
for( let parent = this.parentElement; parent; parent = parent.parentElement)
if( parent.onSlice )
return parent.onSlice(
{ detail: string2value( type, localStorage.getItem( attr( this, 'key' ) ) )
, target: this
} );
For HTML native elements (along with custom elements) with value
the slice update has to be triggered by change
or another event .
🤔 unified approach for DCE embedded elements like local-storage
and native HTML elements is achievable via
- defining the event which would trigger the
slice
update. By default it would be achange
event. Viaslice-update="change"
attribute - the slice data updates taken from
value
element property
default slice update event and value prop
Should slice synchronization event be explicitly defined on slice-update
with slice-prop
?
For minimization and DX reasons, NO. Without slice-update
the engine can assume its value is change
event and the value
property is the data source. When there is a need to change,
slice-update
attribute defines the event. For example, instead of defaultchange
event set it toblur
slice-prop
attribute defined the accessor property. For example, instead of defaultvalue
prop set it tovalidity
, a ValidityState object orselection
, an artificial accessor forinput
andtextarea
utilizing the selectionStart and selectionEnd.
slice-property attribute
Would define the data accessor for slice update. By default it is value
which matches the HTML convention for all form input fields.
form data vs individual fields
The slice
data can be bound as to individual fields as on form level. HTMLFormElement gives the form's elements property which can be mapped to object filled by form element name : value
.
From another hand, the FormData object is used by fetch
layer and can be used as is without transformation when slice is bound by http-request
and constructable from form element:
const formData = new FormData(someFormElement);
slot initialization
- from external data (when slice is mapped to another)
- from instantiated HTML
- ? from detached HTML
Would be whole form data changed on individual input change?
multiple slices and events associated with same element
While the simple value
by change
event
<input slice="user-input" />
is sufficient for many cases, often there is a need for more sophisticated behavior and accessing varios dynamic props on difeerent events.
For example, different UX reaction on invalid input should be during entering the value and after its completion. The change
event meant for editing phase and blur
for completed. The validation part might be looking as into full text value
as into internal validity
state.
implementation options
HTML allows multiple accociations for same element as in for
attribute with space-separated IDs like in output element. But for multiple slices
updated by own events this approach does not work as multiple props have to be coupled with slices by own events.
- couple the event and data source prop in single attribute allowing multiple (event : prop : slice) triplets
<input slice-map="change:value:user-input ; blur:validity:user-input-error">
Which for some reused params can be shortened
<input slice="user-input" slice-update="change blur">
- introduce
slice-update
element withfor
,event
,value
, andslice
.
<input id="inp1">
<slice-update for="inp1" event="change" value="value" slice="user-input">
<slice-update for="inp1" event="blur" value="validity" slice="user-input-error">
While 1st approach is shorter, it looks more like impirical approach with custom data format 😖 To make it worth the existing pattern of style
attribute with key:value is not working as need to list triplets.
The declarative is more verbose, but some can be shortened by default mapping and encapsulation:
<slice-update event="blur" value="validity" slice="user-input-error">
<input slice="user-input" />
</slice-update>
Here the user-input-error
slice taken from 1st embedded element with value
prop by this element change
event. The for
relation is replaced by embedding relation.
The user-input
slice is taken from same element value by its change
event.
slice-update vs generic event
<input id="inp1">
<slice-event for="inp1" event="keydown" slice="user-input-keydown">
slice-update
and slice-event
look similar but serve the different data. The 1st takes data from the input element property, the later from event data itself.
Alternative option is to use artificial "event"
value:
<slice-update event="blur" value="event" slice="user-input-event">
all variations are compatible
Just question what would be simpler to implement first and what would be demanded by devs community?
Candidates for implementation
The simplest use, defaults for prop and event , with slice-update
and slice-prop
<input slice="user-input" />
<input slice="user-input" slice-update="blur change" slice-prop="validity"/>
This case is convenient for validation of individual field. For the access the value
the slot from <form slot="xxx">
is more suited.
For multiple events/props reflection the slice-update
element with all defined ^^ parameters.
Events in slice set
The slice
is filled only during event and used in follow up transformation only. Further transformations related to slices change would not include the event data.
The reason of temporary use of event data is the event "trigger" nature. The each event has to be served and processed independently.
To use the event data later, those have to be transferred into another persistent slice by slice-copy
.
<input slice="xxx" slice-prop="validity" />
<slice-copy from="//slice/xxx" to="//slice/yyy" />
<xsl:if test="//slice/yyy/patternMismatch">
<em>Pattern mismatch error</em>
</xsl:if>
Form validation flow
each input on chage
or blur
would trigger either native ( by element implementation ) or DCE event-driven declarative validation.
The form level validation is trigerred by form submission flow.
The `change` event is available on the `FORM` element
<script type="module" >
document.querySelector('form').addEventListener('change', (event) => {
console.log(`Form element ${event.target.name} has changed.`);
});
</script>
This is a natural choice for validation trigger on the form level and propagate the formData
when slice
is defined on the form element.
Use of validationMessage - TBD
slot initialization
<el slot=SSS
value=VAL>PAYLOAD can be either
- (form?) input with
value
- -||- with value taken from payload as in
<textarea>PAYLOAD</textarea>
- Custom Element with
value
property (attribute?) - element without
value
prop/attr
During DCE instantiation( 1st render ) the form inputs provide the source for data slot
. Later the value change would update the slot data which would trigger re-render cycle. The presence of data in the slot
would prevent the re-nitialization loop.
There is no need to attach the DOM during the initial value extraction as it would follow with re-render cycle.
What if the value=//slot/sss...
in template would override the value
of element?
The value would be picked during initial render. The changed by user value is propagated into data slot
but following render would preserve the element and would not re-inject it with the new value.
In general, it is possible to detect that value
depends on data or have been changed and re-generate element or re-assign its value.
Should the change
event be suppressed in case of re-assigment as would cause the infinite render loop?
Yes. Even with safeguards on cycle count, the loop has to be stopped eventually. To avoid variations of output dependent on number of re-render loop, it has to be prevented from first hand.
Preserving of elements
is essential for Custom Elements as the state can be not serializeable via HTML/attributes. Hence the attributes ( all, not just value
) update should be done via assigning instead of re-render.
What about payload change?
Same. The re-rendered payload would be re-assigned.
Keeping elements without replacement after re-render
When updating the Document Object Model (DOM), it is better to merge the new content with the existing one, instead of replacing the entire DOM for preserving of elements reason described above. However, in order to do this, the system needs to be able to identify the specific element that needs to be updated during sequential transformations. One way to achieve this is by tagging the element markup in the template with generate-id()
or a simple element counter. However, this method only works when the markup generates a single element. If the loop or recurrent call generates the same element multiple times, it is necessary to modify the element tag to reflect the instance number.
JSX for loops and collection iterations requires a key
property explicitly to be defined. This key
can be used as unique identifier for element in the context of parent.
While it can be a required attribute for element in template to be preserved across re-render cycles, in most cases it can be replaced by idex in iteration which can be auto-calculated. Also, the id
attribute nature can serve the same purpose.
So, when the key
is not presented, its value can be
- taken from
id
- computed as the same element on template index.