Skip to content

Commit 6abcc60

Browse files
committed
[Live] Changing data-action-name to action parameters syntax
1 parent 28883f7 commit 6abcc60

File tree

8 files changed

+48
-90
lines changed

8 files changed

+48
-90
lines changed

src/LiveComponent/assets/src/Directive/directives_parser.ts

Lines changed: 5 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,6 @@ export interface Directive {
2525
* An array of unnamed arguments passed to the action
2626
*/
2727
args: string[];
28-
/**
29-
* An object of named arguments
30-
*/
31-
named: any;
3228
/**
3329
* Any modifiers applied to the action
3430
*/
@@ -41,17 +37,8 @@ export interface Directive {
4137
* into an array of directives, with this format:
4238
*
4339
* [
44-
* { action: 'addClass', args: ['foo'], named: {}, modifiers: [] },
45-
* { action: 'removeAttribute', args: ['bar'], named: {}, modifiers: [] }
46-
* ]
47-
*
48-
* This also handles named arguments
49-
*
50-
* save(foo=bar, baz=bazzles)
51-
*
52-
* Which would return:
53-
* [
54-
* { action: 'save', args: [], named: { foo: 'bar', baz: 'bazzles }, modifiers: [] }
40+
* { action: 'addClass', args: ['foo'], modifiers: [] },
41+
* { action: 'removeAttribute', args: ['bar'], modifiers: [] }
5542
* ]
5643
*
5744
* @param {string} content The value of the attribute
@@ -64,10 +51,8 @@ export function parseDirectives(content: string|null): Directive[] {
6451
}
6552

6653
let currentActionName = '';
67-
let currentArgumentName = '';
6854
let currentArgumentValue = '';
6955
let currentArguments: string[] = [];
70-
let currentNamedArguments: any = {};
7156
let currentModifiers: { name: string, value: string | null }[] = [];
7257
let state = 'action';
7358

@@ -86,7 +71,6 @@ export function parseDirectives(content: string|null): Directive[] {
8671
directives.push({
8772
action: currentActionName,
8873
args: currentArguments,
89-
named: currentNamedArguments,
9074
modifiers: currentModifiers,
9175
getString: () => {
9276
// TODO - make a string representation of JUST this directive
@@ -95,36 +79,15 @@ export function parseDirectives(content: string|null): Directive[] {
9579
}
9680
});
9781
currentActionName = '';
98-
currentArgumentName = '';
9982
currentArgumentValue = '';
10083
currentArguments = [];
101-
currentNamedArguments = {};
10284
currentModifiers = [];
10385
state = 'action';
10486
}
10587
const pushArgument = function() {
106-
const mixedArgTypesError = () => {
107-
throw new Error(`Normal and named arguments cannot be mixed inside "${currentActionName}()"`)
108-
}
109-
110-
if (currentArgumentName) {
111-
if (currentArguments.length > 0) {
112-
mixedArgTypesError();
113-
}
114-
115-
// argument names are also trimmed to avoid space after ","
116-
// "foo=bar, baz=bazzles"
117-
currentNamedArguments[currentArgumentName.trim()] = currentArgumentValue;
118-
} else {
119-
if (Object.keys(currentNamedArguments).length > 0) {
120-
mixedArgTypesError();
121-
}
122-
123-
// value is trimmed to avoid space after ","
124-
// "foo, bar"
125-
currentArguments.push(currentArgumentValue.trim());
126-
}
127-
currentArgumentName = '';
88+
// value is trimmed to avoid space after ","
89+
// "foo, bar"
90+
currentArguments.push(currentArgumentValue.trim());
12891
currentArgumentValue = '';
12992
}
13093

@@ -133,16 +96,11 @@ export function parseDirectives(content: string|null): Directive[] {
13396
throw new Error(`The modifier "${currentActionName}()" does not support multiple arguments.`)
13497
}
13598

136-
if (Object.keys(currentNamedArguments).length > 0) {
137-
throw new Error(`The modifier "${currentActionName}()" does not support named arguments.`)
138-
}
139-
14099
currentModifiers.push({
141100
name: currentActionName,
142101
value: currentArguments.length > 0 ? currentArguments[0] : null,
143102
});
144103
currentActionName = '';
145-
currentArgumentName = '';
146104
currentArguments = [];
147105
state = 'action';
148106
}
@@ -196,14 +154,6 @@ export function parseDirectives(content: string|null): Directive[] {
196154
break;
197155
}
198156

199-
if (char === '=') {
200-
// this is a named argument!
201-
currentArgumentName = currentArgumentValue;
202-
currentArgumentValue = '';
203-
204-
break;
205-
}
206-
207157
// add next character to argument
208158
currentArgumentValue += char;
209159

src/LiveComponent/assets/src/dom_utils.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ export function getAllModelDirectiveFromElements(element: HTMLElement): Directiv
141141
const directives = parseDirectives(element.dataset.model);
142142

143143
directives.forEach((directive) => {
144-
if (directive.args.length > 0 || directive.named.length > 0) {
144+
if (directive.args.length > 0) {
145145
throw new Error(
146146
`The data-model="${element.dataset.model}" format is invalid: it does not support passing arguments to the model.`
147147
);
@@ -167,7 +167,7 @@ export function getModelDirectiveFromElement(element: HTMLElement, throwOnMissin
167167
const directives = parseDirectives(formElement.dataset.model || '*');
168168
const directive = directives[0];
169169

170-
if (directive.args.length > 0 || directive.named.length > 0) {
170+
if (directive.args.length > 0) {
171171
throw new Error(
172172
`The data-model="${formElement.dataset.model}" format is invalid: it does not support passing arguments to the model.`
173173
);

src/LiveComponent/assets/src/live_controller.ts

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -118,23 +118,22 @@ export default class LiveControllerDefault extends Controller<HTMLElement> imple
118118
}
119119

120120
action(event: any) {
121-
// using currentTarget means that the data-action and data-action-name
122-
// must live on the same element: you can't add
123-
// data-action="click->live#action" on a parent element and
124-
// expect it to use the data-action-name from the child element
125-
// that actually received the click
126-
const rawAction = event.currentTarget.dataset.actionName;
127-
128-
// data-action-name="prevent|debounce(1000)|save"
121+
const params = event.params;
122+
if (!params.action) {
123+
throw new Error(`No action name provided on element: ${getElementAsTagText(event.currentTarget)}. Did you forget to add the "data-live-action-param" attribute?`);
124+
}
125+
const rawAction = params.action;
126+
// all other params are considered action arguments
127+
const actionArgs = { ...params };
128+
delete actionArgs.action;
129+
130+
// data-live-action-param="debounce(1000)|save"
129131
const directives = parseDirectives(rawAction);
130132
let debounce: number | boolean = false;
131133

132134
directives.forEach((directive) => {
133135
let pendingFiles: { [key: string]: HTMLInputElement } = {};
134136
const validModifiers: Map<string, (modifier: DirectiveModifier) => void> = new Map();
135-
validModifiers.set('prevent', () => {
136-
event.preventDefault();
137-
});
138137
validModifiers.set('stop', () => {
139138
event.stopPropagation();
140139
});
@@ -176,7 +175,7 @@ export default class LiveControllerDefault extends Controller<HTMLElement> imple
176175
}
177176
delete this.pendingFiles[key];
178177
}
179-
this.component.action(directive.action, directive.named, debounce);
178+
this.component.action(directive.action, actionArgs, debounce);
180179

181180
// possible case where this element is also a "model" element
182181
// if so, to be safe, slightly delay the action so that the

src/LiveComponent/assets/test/controller/action.test.ts

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ describe('LiveController Action Tests', () => {
2323
<div ${initComponent(data)}>
2424
${data.isSaved ? 'Comment Saved!' : ''}
2525
26-
<button data-action="live#action" data-action-name="save">Save</button>
26+
<button data-action="live#action" data-live-action-param="save">Save</button>
2727
</div>
2828
`);
2929

@@ -46,7 +46,7 @@ describe('LiveController Action Tests', () => {
4646
4747
${data.isSaved ? 'Comment Saved!' : ''}
4848
49-
<button data-action="live#action" data-action-name="save">Save</button>
49+
<button data-action="live#action" data-live-action-param="save">Save</button>
5050
</div>
5151
`);
5252

@@ -73,11 +73,17 @@ describe('LiveController Action Tests', () => {
7373

7474
it('Sends action with named args', async () => {
7575
const test = await createTest({ isSaved: false}, (data: any) => `
76-
<div ${initComponent(data)}>
77-
${data.isSaved ? 'Component Saved!' : ''}
76+
<div ${initComponent(data)}>
77+
${data.isSaved ? 'Component Saved!' : ''}
7878
79-
<button data-action="live#action" data-action-name="sendNamedArgs(a=1, b=2, c=3)">Send named args</button>
80-
</div>
79+
<button
80+
data-action="live#action"
81+
data-live-action-param="sendNamedArgs"
82+
data-live-a-param="1"
83+
data-live-b-param="2"
84+
data-live-c-param="3"
85+
>Send named args</button>
86+
</div>
8187
`);
8288

8389
// ONLY a post is sent, not a re-render GET
@@ -99,7 +105,7 @@ describe('LiveController Action Tests', () => {
99105
<select
100106
data-model="on(change)|food"
101107
data-action="live#action"
102-
data-action-name="changeFood"
108+
data-live-action-param="changeFood"
103109
>
104110
<option value="" ${data.food === '' ? 'selected' : ''}>Choose a food</option>
105111
<option value="pizza" ${data.pizza === '' ? 'selected' : ''}>Pizza</option>
@@ -131,7 +137,7 @@ describe('LiveController Action Tests', () => {
131137
132138
<span>${data.comment}</span>
133139
134-
<button data-action="live#action" data-action-name="save">Save</button>
140+
<button data-action="live#action" data-live-action-param="save">Save</button>
135141
</div>
136142
`);
137143

@@ -170,8 +176,8 @@ describe('LiveController Action Tests', () => {
170176
const test = await createTest({ isSaved: false }, (data: any) => `
171177
<div ${initComponent(data)}>
172178
${data.isSaved ? 'Component Saved!' : ''}
173-
<button data-action="live#action" data-action-name="debounce(10)|save">Save</button>
174-
<button data-action="live#action" data-action-name="debounce(10)|sync(syncAll=1)">Sync</button>
179+
<button data-action="live#action" data-live-action-param="debounce(10)|save">Save</button>
180+
<button data-action="live#action" data-live-action-param="debounce(10)|sync" data-live-sync-all-param="1">Sync</button>
175181
</div>
176182
`);
177183

src/LiveComponent/assets/test/controller/error.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ describe('LiveController Error Handling', () => {
2626
const test = await createTest({ counter: 4 }, (data: any) => `
2727
<div ${initComponent(data)}>
2828
Current count: ${data.counter}
29-
<button data-action="live#action" data-action-name="save">Save</button>
29+
<button data-action="live#action" data-live-action-param="save">Save</button>
3030
<button data-action="live#$render">Render</button>
3131
</div>
3232
`);
@@ -62,7 +62,7 @@ describe('LiveController Error Handling', () => {
6262
const test = await createTest({ }, (data: any) => `
6363
<div ${initComponent(data)}>
6464
Original component text
65-
<button data-action="live#action" data-action-name="save">Save</button>
65+
<button data-action="live#action" data-live-action-param="save">Save</button>
6666
</div>
6767
`);
6868

src/LiveComponent/assets/test/controller/loading.test.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -81,8 +81,8 @@ describe('LiveController data-loading Tests', () => {
8181
<div ${initComponent(data)}>
8282
<span data-loading="action(save)|show" data-testid="loading-element">Loading...</span>
8383
84-
<button data-action="live#action" data-action-name="save">Save</button>
85-
<button data-action="live#action" data-action-name="otherAction">Other Action</button>
84+
<button data-action="live#action" data-live-action-param="save">Save</button>
85+
<button data-action="live#action" data-live-action-param="otherAction">Other Action</button>
8686
<button data-action="live#$render">Re-Render</button>
8787
</div>
8888
`);
@@ -176,8 +176,8 @@ describe('LiveController data-loading Tests', () => {
176176
<div ${initComponent(data)}>
177177
<span data-loading="action(otherAction)|show" data-testid="loading-element">Loading...</span>
178178
179-
<button data-action="live#action" data-action-name="debounce(50)|save">Save</button>
180-
<button data-action="live#action" data-action-name="otherAction">Other Action</button>
179+
<button data-action="live#action" data-live-action-param="debounce(50)|save">Save</button>
180+
<button data-action="live#action" data-live-action-param="otherAction">Other Action</button>
181181
</div>
182182
`);
183183

@@ -203,7 +203,7 @@ describe('LiveController data-loading Tests', () => {
203203
<div ${initComponent(data)}>
204204
<span data-loading="action(save)|delay(50)|show" data-testid="loading-element">Loading...</span>
205205
206-
<button data-action="live#action" data-action-name="save">Save</button>
206+
<button data-action="live#action" data-live-action-param="save">Save</button>
207207
</div>
208208
`);
209209

src/LiveComponent/assets/test/controller/query-binding.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ describe('LiveController query string binding', () => {
149149
const test = await createTest({ prop: ''}, (data: any) => `
150150
<div ${initComponent(data, {queryMapping: {prop: {name: 'prop'}}})}>
151151
Prop: ${data.prop}
152-
<button data-action="live#action" data-action-name="changeProp">Change prop</button>
152+
<button data-action="live#action" data-live-action-param="changeProp">Change prop</button>
153153
</div>
154154
`);
155155

@@ -165,4 +165,4 @@ describe('LiveController query string binding', () => {
165165

166166
expectCurrentSearch().toEqual('?prop=foo');
167167
});
168-
})
168+
})

src/LiveComponent/src/Form/Type/LiveCollectionType.php

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,8 @@ public function buildView(FormView $view, FormInterface $form, array $options):
4747

4848
$attr = $view->vars['button_add']->vars['attr'];
4949
$attr['data-action'] ??= 'live#action';
50-
$attr['data-action-name'] ??= sprintf('addCollectionItem(name=%s)', $view->vars['full_name']);
50+
$attr['data-live-action-param'] ??= 'addCollectionItem';
51+
$attr['data-live-name-param'] ??= $view->vars['full_name'];
5152
$view->vars['button_add']->vars['attr'] = $attr;
5253

5354
array_splice($view->vars['button_add']->vars['block_prefixes'], 1, 0, 'live_collection_button_add');
@@ -85,7 +86,9 @@ public function finishView(FormView $view, FormInterface $form, array $options):
8586

8687
$attr = $entryView->vars['button_delete']->vars['attr'];
8788
$attr['data-action'] ??= 'live#action';
88-
$attr['data-action-name'] ??= sprintf('removeCollectionItem(name=%s, index=%s)', $view->vars['full_name'], $k);
89+
$attr['data-live-action-param'] ??= 'removeCollectionItem';
90+
$attr['data-live-name-param'] ??= $view->vars['full_name'];
91+
$attr['data-live-index-param'] ??= $k;
8992
$entryView->vars['button_delete']->vars['attr'] = $attr;
9093

9194
array_splice($entryView->vars['button_delete']->vars['block_prefixes'], 1, 0, 'live_collection_button_delete');

0 commit comments

Comments
 (0)