Skip to content

Commit e232cc5

Browse files
authored
Ensure _target is sent as "undefined" when it doesn't exist (#3731)
Fixes #3727. In LV <= 1.0.5 we sent the `_target` as part of the url encoded form values, but in 1.0.6 we switched to sending the meta values directly in the form event to support `JS.push`'s value parameter for nested values. Since the event itself is JSON encoded, this meant that any keys with undefined value would be dropped by JS. To be backwards compatible, we now ensure that the `_target` is always sent and restore the old behavior of it being the string `"undefined"`, although that seems a bit ugly. It is what it is now...
1 parent 4b5f68f commit e232cc5

File tree

2 files changed

+33
-1
lines changed

2 files changed

+33
-1
lines changed

assets/js/phoenix_live_view/view.js

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1212,7 +1212,14 @@ export default class View {
12121212
type: "form",
12131213
event: phxEvent,
12141214
value: formData,
1215-
meta: {_target: opts._target, ...meta},
1215+
meta: {
1216+
// no target was implicitly sent as "undefined" in LV <= 1.0.5, therefore
1217+
// we have to keep it. In 1.0.6 we switched from passing meta as URL encoded data
1218+
// to passing it directly in the event, but the JSON encode would drop keys with
1219+
// undefined values.
1220+
_target: opts._target || "undefined",
1221+
...meta
1222+
},
12161223
uploads: uploads,
12171224
cid: cid
12181225
}

assets/test/view_test.js

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,31 @@ describe("View + DOM", function(){
276276
view.pushInput(input, el, null, "validate", {_target: input.name, value: optValue})
277277
})
278278

279+
test("pushInput with nameless input", function(){
280+
expect.assertions(4)
281+
282+
let liveSocket = new LiveSocket("/live", Socket)
283+
let el = liveViewDOM()
284+
let input = el.querySelector("input")
285+
input.removeAttribute("name")
286+
simulateUsedInput(input)
287+
let view = simulateJoinedView(el, liveSocket)
288+
let channelStub = {
289+
push(_evt, payload, _timeout){
290+
expect(payload.type).toBe("form")
291+
expect(payload.event).toBeDefined()
292+
expect(payload.value).toBe("_unused_note=&note=2")
293+
expect(payload.meta).toEqual({"_target": "undefined"})
294+
return {
295+
receive(){ return this }
296+
}
297+
}
298+
}
299+
view.channel = channelStub
300+
301+
view.pushInput(input, el, null, "validate", {_target: input.name})
302+
})
303+
279304
test("getFormsForRecovery", function(){
280305
let view, html, liveSocket = new LiveSocket("/live", Socket)
281306

0 commit comments

Comments
 (0)