Adding reactive pages

In Genie Framework, the Stipple.jl package implements a reactive UI layer that enables dynamic interactivity with the UI. This is useful for building apps that require real-time updates, such as dashboards, data visualizations, and simulations.

We refer to this type of interfaces as reactive, since the app instantly reacts to a user action by executing some code and updating the UI. All without having to reload the page. This is made possible by the Javascript code provided by Stipple.jl that enables two-way synchronization between the browser and the server.

There are several possible patterns for apps with reactive pages. For more details on building reactive apps, see the Your first dashboard guide and the docs.

Single app module with multiple pages

When building apps without too much logic, it might be sufficient to keep it all in a single module even if there's multiple pages. You just need to define additional routes for each page as in this example, which uses the StatisticAnalysis module defined here:

app.jl
module App
using GenieFramework
using Statistics
@genietools

# Implement reactive code
@app begin
    @in N = 0
    @out m = 0.0
    @out name = "John"
    @onchange N begin
        m = mean(rand(N))
    end
end

# Define the UI for each page
index() = [h1("Welcome {{name}}!"), a(href="/form")]
function formui()
    cell([
        textfield("How many numbers?", :N),
        p("The average of {{N}} random numbers is {{m}}"),
    ])
end


# Define the routes
@page("/", index)
@page("/form", formui)
end

Alternatively, you can place the UI code in a separate file and include it as

app.jl
@page("/", "ui.jl")
ui.jl
    cell([
        textfield("How many numbers?", :N),
        p("The average of {{N}} random numbers is {{m}}"),
    ])

Multiple app modules

If each page performs different functions, for instance a dashboard page and a another page with a configuration panel, you can implement them in separate logic modules. Then, simply include each module in the main app.jl as in this example:

app.jl
module App
using GenieFramework
include("Index.jl")
include("Form.jl")
end
Index.jl
module Index
using GenieFramework

@app begin
    @out name = "John"
end

function ui()
    h1("Welcome {{name}}!"),
end

@page("/", ui)
end
Form.jl
module Form
using GenieFramework
using Statistics

@app begin
    @in N = 0
    @out m = 0.0
    @onchange N begin
        m = mean(rand(N))
    end
end

function ui()
    cell([
        textfield("How many numbers?", :N),
        p("The average of {{N}} random numbers is {{m}}"),
    ])
end

@page("/form", ui)
end