POST
Sputnik project, third update
Create nestable custom widgets in Julia
Since the last update I have mainly been working on tools for web app creation in Julia. The work has been on two fronts:
on the techical side, I transitioned from using Vue.js to using Knockout.js to sync Julia values to Javascript values
on the user facing side, I've been working on a framework for custom widgets creation, so that using a
@widget
macro users can define their own custom widgets / recipes to visualize their custom types with simple code
Knockout.jl
Concerning point 1, Knockout.jl allows two-way binding between Julia and Javascript values.
The following Julia code:
using Knockout, WebIO, Observables
template = Node(:p, "{{message}}", attributes = Dict("data-bind" => "visible : visible"))
msg = Observable("hello")
vis = Observable(true)
knockout(template, [:message=>msg, :visible=>vis])
will display "hello"
but will hide it if we set:
vis[] = false
To change the text we should simply change the Julia Observable
:
mgs[] = "Good bye"
InteractBase.jl now uses Knockout.jl to sync the value of its widgets on-screen with the corresponding Julia values.
Widget "recipes"
Concerning the second point, Widgets.jl offers the @widget
macro to create custom widgets. The macro needs a function call:
@widget wdg function mywidget(df::DataFrame)
:select = dropdown(names(df))
:btn = button("Plot histogram")
@output! wdg ($(:btn); histogram(df[:select[]]))
@layout! wdg vbox(hbox(:select, :btn), _.output)
end
where symbols correspond to "children" that will form the new UI, with a structure specified by _.layout
. _.output
will denote the output of the UI. Symbols refer to other widgets, you can either use :select[]
to mean "put here the value of :select
"", or $(:select)
which means "put here the value of :select
and update whenever :select
changes". In this case for example, _.output
will update when pressing :btn
but not when changing :select
.
Is it possible to have separate _.output
and _.display
, where _.output
is what you want the UI to return and _.display
is how you want to show it. For example:
@widget wdg function mywidget(df::DataFrame)
:select = dropdown(names(df))
:btn = button("Plot histogram")
@output! wdg ($(:btn); df[:select[]]) # return the column
@display! wdg histogram($(_.output)) # plot histogram
@layout! wdg vbox(hbox(:select, :btn), _.display)
end
The UI can then be launched with any DataFrame
:
using Plots, DataFrames
df = DataFrame(x = rand(100), y = randn(100), z = rand(["Male", "Female"], 100))
ui = mywidget(df)
The output of ui
has been defined to be the select column and you can access that observable with observe(ui)
.