Skip to content

Commit cb40b5a

Browse files
authored
Merge pull request #140 from plotly/pattern_match_output_fix
Single wildcards output fix
2 parents aa3d51b + 52f068d commit cb40b5a

File tree

2 files changed

+66
-11
lines changed

2 files changed

+66
-11
lines changed

src/handler/processors/callback.jl

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
1+
function split_single_callback_id(callback_id::AbstractString)
2+
parts = rsplit(callback_id, ".")
3+
return (id = parts[1], property = parts[2])
4+
end
15
function split_callback_id(callback_id::AbstractString)
26
if startswith(callback_id, "..")
37
result = []
4-
append!.(Ref(result), split_callback_id.(split(callback_id[3:end-2], "...", keepempty = false)))
8+
push!.(Ref(result), split_single_callback_id.(split(callback_id[3:end-2], "...", keepempty = false)))
59
return result
610
end
7-
parts = rsplit(callback_id, ".")
8-
return [(id = parts[1], property = parts[2])]
11+
return split_single_callback_id(callback_id)
912
end
1013

1114
input_to_arg(input) = get(input, :value, nothing)
@@ -50,8 +53,7 @@ function process_callback_call(app, callback_id, outputs, inputs, state)
5053
return Dict(:response=>response, :multi=>true)
5154
end
5255

53-
outputs_to_vector(out::Vector) = out
54-
outputs_to_vector(out) = [out]
56+
outputs_to_vector(out, is_multi) = is_multi ? out : [out]
5557

5658
function process_callback(request::HTTP.Request, state::HandlerState)
5759
app = state.app
@@ -61,11 +63,14 @@ function process_callback(request::HTTP.Request, state::HandlerState)
6163
inputs = get(params, :inputs, [])
6264
state = get(params, :state, [])
6365
output = Symbol(params[:output])
64-
outputs_list = outputs_to_vector(get(params, :outputs, split_callback_id(params[:output])))
65-
changedProps = get(params, :changedPropIds, [])
66-
context = CallbackContext(response, outputs_list, inputs, state, changedProps)
6766

6867
try
68+
is_multi = is_multi_out(app.callbacks[output])
69+
outputs_list = outputs_to_vector(
70+
get(params, :outputs, split_callback_id(params[:output])),
71+
is_multi)
72+
changedProps = get(params, :changedPropIds, [])
73+
context = CallbackContext(response, outputs_list, inputs, state, changedProps)
6974
cb_result = with_callback_context(context) do
7075
process_callback_call(app, output, outputs_list, inputs, state)
7176
end

test/callbacks.jl

Lines changed: 53 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -382,7 +382,7 @@ end
382382

383383
end
384384

385-
@testset "pattern-match ALL" begin
385+
@testset "pattern-match ALL single out" begin
386386
app = dash()
387387
app.layout = html_div() do
388388
dcc_input(id = (type="test", index = 1), value="initial value", type = "text"),
@@ -412,10 +412,8 @@ end
412412
request = (
413413
output = string(out_key),
414414
outputs = [
415-
[
416415
(id = (index=1, type="test-out"), property = "children"),
417416
(id = (index=2, type="test-out"), property = "children")
418-
]
419417
],
420418
changedPropIds = [changed_key],
421419
inputs = [
@@ -435,6 +433,58 @@ end
435433
@test resp_obj.response.var"{\"index\":1,\"type\":\"test-out\"}".children =="test 1"
436434
@test resp_obj.response.var"{\"index\":2,\"type\":\"test-out\"}".children =="test"
437435

436+
end
437+
@testset "pattern-match ALL multi out" begin
438+
app = dash()
439+
app.layout = html_div() do
440+
dcc_input(id = (type="test", index = 1), value="initial value", type = "text"),
441+
dcc_input(id = (type="test", index = 2), value="initial value", type = "text"),
442+
html_div(id = (type = "test-out", index = 1)),
443+
html_div(id = (type = "test-out", index = 2))
444+
end
445+
446+
first_key = """{"index":1,"type":"test"}.value"""
447+
changed_key = """{"index":2,"type":"test"}.value"""
448+
callback!(app, [Output((type = "test-out", index = ALL), "children")], Input((type="test", index = ALL), "value")) do value
449+
context = callback_context()
450+
@test haskey(context.inputs, first_key)
451+
@test context.inputs[first_key] == "test 1"
452+
@test haskey(context.inputs, changed_key)
453+
@test context.inputs[changed_key] == "test"
454+
@test length(context.triggered) == 1
455+
@test context.triggered[1].prop_id == changed_key
456+
@test context.triggered[1].value == "test"
457+
return [value]
458+
end
459+
@test length(app.callbacks) == 1
460+
out_key = Symbol("""..{"index":["ALL"],"type":"test-out"}.children..""")
461+
@test haskey(app.callbacks, out_key)
462+
463+
handler = Dash.make_handler(app)
464+
request = (
465+
output = string(out_key),
466+
outputs = [[
467+
(id = (index=1, type="test-out"), property = "children"),
468+
(id = (index=2, type="test-out"), property = "children")
469+
]],
470+
changedPropIds = [changed_key],
471+
inputs = [
472+
[
473+
(id = (index=1, type="test"), property = "value", value = "test 1"),
474+
(id = (index=2, type="test"), property = "value", value = "test")
475+
]
476+
]
477+
)
478+
test_json = JSON2.write(request)
479+
request = HTTP.Request("POST", "/_dash-update-component", [], Vector{UInt8}(test_json))
480+
response = HTTP.handle(handler, request)
481+
@test response.status == 200
482+
resp_obj = JSON2.read(String(response.body))
483+
@test in(:multi, keys(resp_obj))
484+
485+
@test resp_obj.response.var"{\"index\":1,\"type\":\"test-out\"}".children =="test 1"
486+
@test resp_obj.response.var"{\"index\":2,\"type\":\"test-out\"}".children =="test"
487+
438488
end
439489

440490
@testset "invalid multi out" begin

0 commit comments

Comments
 (0)