Open Vinai opened 3 years ago
Whatever approach comes up on top, I'll first create a prototype to see how it feels to use it. Any feedback or additional ideas are very welcome.
Other alternatives:
observer
attribute so that for simple scripts it is as easy to use as A: <event on="click" observer="console.log(this)">
I do like the <event>
approach and I think with one or more of the mentioned adjustments we can make it more accessible too
Note to self: if using B or C there should be a special events that is triggered before and after the initial render. Maybe something like
<event on="init"/>
<event on="render"/>
I'll start by implementing option B (Generic event child elements with convention based event names).
To try this out only grid actions will support events initially. Generic vents for rows and buttons will be added later once things stabilize.
If needed an attribute to specify custom events can still be added in a backward compatible manner later.
The API for the action event node might be removed or changed in future.
Specifying event triggers on actions allows creating complex ui customizations. Only the event trigger can be specified in the grid XML:
<actions>
<action id="delete" label="Delete" url="*/*/delete">
<event on="click"/>
</action>
</actions>
The event name is built based on the grid name, the action id and the event trigger:
private function getEventName(): string
{
$gridNameInEvent = $this->eventify($this->gridName);
return sprintf('hyva-grid-%s-action-%s-%s', $gridNameInEvent, $this->eventify($this->targetId), $this->on);
}
For example, given a grid named products-query-grid, and an action with the id delete, the JavaScript event that is dispatched is
hyva-grid-products-query-grid-action-delete-click
Event subscribers can be declared in .phtml template files that are added to the grid page via layout XML.
Example:
<script>
window.addEventListener('hyva-grid-products-grid-action-delete-click', e => {
if (! confirm('<?= __('Are you sure?') ?>')) {
e.detail.origEvent.preventDefault();
}
});
</script>
The event arguments can be retrieved from the events.detail property in subscribers.
This is the original event that was triggered by the user interaction.
probably this is mainly useful to abort user actions with event.detail.origEvent.preventDefault()
.
This property is a reference to the clicked grid table row.
It might be useful to retrieve the rendered cell values in a kind of hacky way.
This is the Alpine.js view model of the grid.
This is the grid action id. In the examples on this page it is the string delete
.
This is the map of parameters that would be passed to the URL. It depends on the action configuration.
The following example will add the params {foo => idValue}
:
<actions idColumn="id">
<action id="delete" label="Delete" url="*/*/delete" idParam="foo">
<event on="click"/>
</action>
</actions>
Issue Description
This Issue is to document the decisions regarding how to enable developers to trigger JavaScript on visitor actions, and to gather feedback.
Originally I started thinking about it in relation to the forms (issue #27), but @Fabian Schmengler has a use case for the grids, too (see #34).
I think a common solution should be used.
A) Event specific attributes with native JS expressions
The idea is to add attributes like
onchange
,onclick
,onfocus
and so on to field and action elements, and the value could be rendered into the generated HTML directly. For exampleThis would result in an HTML element like this:
Pros of this approach:
Cons of this approach:
showPopup
in the above expression would have to be declared on thewindow
in global scope, unless more work is done to make the alpineJs view model extensible.onclick
values would be overwritten during configuration merging.B) Generic event child elements with convention based event names
In this approach,
event
elements can be added as children to supported grid and form nodes. For example:This would result in the following HTML:
For grids the event name would include the grid-name and the action-id following the pattern in the example above (the last part would depend on the event, i.e.
click
,keydown
, etc). For forms the event name would follow the patternhyva_form_[form-name]_[field-name]_[event-type]
.Grid and form names would need to be normalized so they work in event names, that is, lowercase characters and underscores only.
The above example HTML would actially be slightly more complex because event arguments would need to be added to the dispatch.
Pros of this approach:
tr
row element and the view model, and for forms the field element and also the view model.Cons of this approach:
C) Generic event child elements with configurable event names
This approach is very similar to approach B), except that each
event
can specify a custom event name. For example:This would result in the following HTML:
The above example HTML would actially be slightly more complex because event arguments would need to be added to the dispatch.
Pros of this approach:
tr
row element and the view model, and for forms the field element and also the view model.Cons of this approach:
enabled
attribute cold be added which would allow disabling events declared by other modules (but is this even needed?)D) Native events only with external subscribers
Any HTML element can be observed by subscribers that add attach programmatically. This already is possible and require no knowledge beyond native JavaScript and the DOM model.
Pros of this approach:
Cons of this approach: