{litter}

John Coene

Before we start

Bad ideas


I have already been told that:


  • {litter} is a bad package name.
  • Injecting random emojis in the presentation is a bad idea.

What is {litter}?

Shiny inputs, but different…

The twist

But Why?

Primarily dynamically generating inputs.


Generated IDs make a mess server-side.

observeEvent(data()), {
  lapply(seq_along(data()), \(i){
    observeEvent(input[[paste0("btn", i)]], {
      # ...
    })
  })
})

Something’s not quite right

Different inputs displayed but same server-side logic.

What I want


  • Multiple inputs UI-side
  • Logic encompassed in a single code-block server-side


$("body").on("click", ".btn", (event) => {})

An Example

Introduction

Retrieve records and allow the following operations:

  • Create
  • Replace
  • Update
  • Delete


Everything is dynamically generated.

UI

records |>
  lapply(\(record) {
    div(
      litTextInput(
        name = "val",
        value = record$val, 
        index = record$index
      ),
      litActionButton(
        name = "del", 
        content = "Delete", 
        index = record$index
      )
    )
  })

Server

observeEvent(input$val, {
  query <- sprintf(
    "UPDATE table SET val = '%s' WHERE index = %s",
    input$val$value,
    input$val$props$index
  )
  dbExecute(con, query)
})

observeEvent(input$del, {
  query <- sprintf(
    "DELETE FROM table WHERE index = %s",
    input$del$props$index
  )
  dbExecute(con, query)
})

Props

Distinguish between inputs.

UI

litTextInput(
  name = "val",
  value = "something",
  my_value = "hello"
)

litTextInput(
  name = "val",
  value = "something else",
  my_value = "world"
)

Input value

# input$val
list(
  props = list(
    my_value = "hello"
  ),
  value = "something"
)

list(
  props = list(
    my_value = "world"
  ),
  value = "something else"
)

Props ~ input metadata

Closing

Conventions

  • All input functions start in lit.
  • All inputs have a value
  • All inputs can be updated with update_input()
  • Labels are not part of the input
  • All inputs accept a send_on_render argument
  • All inputs return data in the same format:
list(
  props = list(),
  id = "", # omitted if not set
  value = 1L
)

Think {litter}


  • input is used to communicate not store values.
  • React to the input change.

Limitations


  • Only works with bslib’s Bootstrap 5.
  • These inputs are not captured by Shiny’s bookmarking session
  • These inputs are not captured by shinytest2

These limitations are unlikely to be lifted in the future.

Thank you!

John Coene

the-y-company.com

opifex.org

@jdatap

linkedin.com/in/johncoene