Skip to content

Commit f76b97f

Browse files
committed
Send live action arguments to backend
1 parent 39d4e49 commit f76b97f

File tree

3 files changed

+75
-4
lines changed

3 files changed

+75
-4
lines changed

src/LiveComponent/assets/dist/live_controller.js

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1070,7 +1070,7 @@ class default_1 extends Controller {
10701070
directives.forEach((directive) => {
10711071
const _executeAction = () => {
10721072
this._clearWaitingDebouncedRenders();
1073-
this._makeRequest(directive.action);
1073+
this._makeRequest(directive.action, directive.args.length > 0 ? directive.args : directive.named);
10741074
};
10751075
let handled = false;
10761076
directive.modifiers.forEach((modifier) => {
@@ -1162,11 +1162,23 @@ class default_1 extends Controller {
11621162
}, this.debounceValue || DEFAULT_DEBOUNCE);
11631163
}
11641164
}
1165-
_makeRequest(action) {
1165+
_makeRequest(action, values) {
11661166
const splitUrl = this.urlValue.split('?');
11671167
let [url] = splitUrl;
11681168
const [, queryString] = splitUrl;
11691169
const params = new URLSearchParams(queryString || '');
1170+
let valueParams = null;
1171+
if (Array.isArray(values)) {
1172+
valueParams = new URLSearchParams();
1173+
values.forEach((v, i) => valueParams.set(i, v));
1174+
}
1175+
else if (typeof values === 'object' && Object.keys(values).length > 0) {
1176+
valueParams = new URLSearchParams();
1177+
Object.keys(values).forEach(k => valueParams.set(k, values[k]));
1178+
}
1179+
if (valueParams !== null) {
1180+
params.set('values', valueParams.toString());
1181+
}
11701182
const fetchOptions = {};
11711183
fetchOptions.headers = {
11721184
'Accept': 'application/vnd.live-component+json',

src/LiveComponent/assets/src/live_controller.ts

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ export default class extends Controller {
144144
// taking precedence
145145
this._clearWaitingDebouncedRenders();
146146

147-
this._makeRequest(directive.action);
147+
this._makeRequest(directive.action, directive.args.length > 0 ? directive.args : directive.named);
148148
}
149149

150150
let handled = false;
@@ -296,11 +296,24 @@ export default class extends Controller {
296296
}
297297
}
298298

299-
_makeRequest(action: string|null) {
299+
_makeRequest(action: string|null, values: Array<string>|object) {
300300
const splitUrl = this.urlValue.split('?');
301301
let [url] = splitUrl
302302
const [, queryString] = splitUrl;
303303
const params = new URLSearchParams(queryString || '');
304+
let valueParams = null;
305+
306+
if (Array.isArray(values)) {
307+
valueParams = new URLSearchParams();
308+
309+
values.forEach((v, i) => valueParams.set(i, v));
310+
} else if (typeof values === 'object' && Object.keys(values).length > 0) {
311+
valueParams = new URLSearchParams(values);
312+
}
313+
314+
if (valueParams !== null) {
315+
params.set('values', valueParams.toString());
316+
}
304317

305318
const fetchOptions: RequestInit = {};
306319
fetchOptions.headers = {

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

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,16 @@ describe('LiveController Action Tests', () => {
2929
>
3030
</label>
3131
32+
${data.isChanged ? 'Comment Changed!' : ''}
3233
${data.isSaved ? 'Comment Saved!' : ''}
3334
3435
<button
3536
data-action="live#action"
3637
data-action-name="save"
3738
>Save</button>
39+
40+
<button data-action="live#action" data-action-name="updateSimple(a, b, c)">Update simple</button>
41+
<button data-action="live#action" data-action-name="updateNamed(a=1, b=2, c=3)">Update named</button>
3842
</div>
3943
`;
4044

@@ -64,4 +68,46 @@ describe('LiveController Action Tests', () => {
6468

6569
expect(postMock.lastOptions().body.get('comments')).toEqual('hi WEAVER');
6670
});
71+
72+
it('Sends action simple args', async () => {
73+
const data = { comments: 'hi' };
74+
const { element } = await startStimulus(template(data));
75+
76+
const postMock = fetchMock.postOnce('http://localhost/_components/my_component/updateSimple?values=0%3Da%261%3Db%262%3Dc', {
77+
html: template({ comments: ' a b c', isChanged: true }),
78+
data: { isChanged: true }
79+
});
80+
81+
await userEvent.type(getByLabelText(element, 'Comments:'), 'a b c');
82+
83+
getByText(element, 'Update simple').click();
84+
85+
await waitFor(() => expect(element).toHaveTextContent('Comment Changed!'));
86+
expect(getByLabelText(element, 'Comments:')).toHaveValue(' a b c');
87+
88+
fetchMock.done();
89+
90+
expect(postMock.lastOptions().body.get('comments')).toEqual('hia b c');
91+
});
92+
93+
it('Sends action named args', async () => {
94+
const data = { comments: 'hi' };
95+
const { element } = await startStimulus(template(data));
96+
97+
const postMock = fetchMock.postOnce('http://localhost/_components/my_component/updateNamed?values=a%3D1%26b%3D2%26c%3D3', {
98+
html: template({ comments: ' a=1 b=2 c=3', isChanged: true }),
99+
data: { isChanged: true }
100+
});
101+
102+
await userEvent.type(getByLabelText(element, 'Comments:'), 'a b c');
103+
104+
getByText(element, 'Update named').click();
105+
106+
await waitFor(() => expect(element).toHaveTextContent('Comment Changed!'));
107+
expect(getByLabelText(element, 'Comments:')).toHaveValue(' a=1 b=2 c=3');
108+
109+
fetchMock.done();
110+
111+
expect(postMock.lastOptions().body.get('comments')).toEqual('hia b c');
112+
});
67113
});

0 commit comments

Comments
 (0)