LocalStorage Usage Guide
A conversation with ChatGPT 4o about storing data in the browser using JavaScript with Shiny. See the original conversation on OpenAI.
Prompt
I’m in a workshop at posit::conf(2024) learning about using JavaScript with Shiny for R. Can you show me how to write to and read from local storage in the browser using JavaScript? Show me just the JavaScript snippets I need to know with a little bit of explanation. Don’t show me a full HTML example, though, because I’ll be using this in a Shiny app.
ChatGPT
Sure! Here are the JavaScript snippets you need to work with local storage in a browser:
Writing to Local Storage
To save data to local storage, you use the localStorage.setItem
method. Here’s a simple example:
// Save a string value localStorage.setItem('key', 'value');
// Save a JavaScript object (you need to stringify it first)
const myObject = { name: 'John', age: 30 };
.setItem('myObject', JSON.stringify(myObject)); localStorage
Reading from Local Storage
To retrieve data from local storage, you use the localStorage.getItem
method. Here’s how you do it:
// Retrieve a string value
const value = localStorage.getItem('key');
console.log(value); // Outputs: 'value'
// Retrieve a JavaScript object (you need to parse it back to an object)
const retrievedObject = JSON.parse(localStorage.getItem('myObject'));
console.log(retrievedObject); // Outputs: { name: 'John', age: 30 }
Removing an Item from Local Storage
If you need to remove an item from local storage, you can use the localStorage.removeItem
method:
.removeItem('key'); localStorage
Clearing All Local Storage
To clear all data from local storage, you can use the localStorage.clear
method:
.clear(); localStorage
These snippets cover the basic operations for working with local storage. You can integrate them into your Shiny app’s JavaScript code as needed.
Prompt
I’m writing a Shiny for R app and want to store a variable in local storage so that the next time the user starts the app, I can retrieve the stored value, send it to the server, and initialize an input with the stored value. Show me how to do this, including a simple example. Use bslib for the UI. Don’t explain everything in the example app, just explain the JavaScript portion
ChatGPT
Sure! Here’s how you can achieve this in a Shiny app with bslib for the UI. The key parts are the JavaScript snippets for storing and retrieving the value from local storage and sending it to the server.
Shiny App Example
library(shiny)
library(bslib)
<- fluidPage(
ui theme = bs_theme(bootswatch = "flatly"),
$head(
tags$script(HTML(
tags"
// Store a variable in local storage when the user inputs a value
Shiny.addCustomMessageHandler('storeValue', function(message) {
localStorage.setItem('storedValue', message.value);
});
// Retrieve the stored value from local storage when the app initializes
document.addEventListener('DOMContentLoaded', function() {
var storedValue = localStorage.getItem('storedValue');
if (storedValue !== null) {
Shiny.setInputValue('storedValue', storedValue);
}
});
"
))
),titlePanel("Shiny Local Storage Example"),
sidebarLayout(
sidebarPanel(
textInput("inputText", "Enter some text:", value = ""),
actionButton("saveBtn", "Save to Local Storage")
),mainPanel(
textOutput("outputText")
)
)
)
<- function(input, output, session) {
server observeEvent(input$saveBtn, {
$sendCustomMessage("storeValue", list(value = input$inputText))
session
})
observeEvent(input$storedValue, {
updateTextInput(session, "inputText", value = input$storedValue)
})
$outputText <- renderText({
outputpaste("Stored value is:", input$inputText)
})
}
shinyApp(ui = ui, server = server)
JavaScript Explanation
Storing the Value:
- The JavaScript code listens for a custom message (
storeValue
) from the Shiny server. - When the message is received, it stores the value in local storage using
localStorage.setItem
.
- The JavaScript code listens for a custom message (
Retrieving the Value:
- When the document is loaded (
DOMContentLoaded
event), the JavaScript code checks if there’s a stored value in local storage. - If a value exists, it sets this value to a Shiny input (
storedValue
) usingShiny.setInputValue
.
- When the document is loaded (
By incorporating these JavaScript snippets into your Shiny app, you can store and retrieve values from local storage, allowing for persistent input across sessions.
Prompt
In the release notes for Shiny 1.9.0, I read the following:
the
Shiny
object has a new propertyinitializedPromise
, which is a Promise-like object that can be awaited or chained with.then()
. This Promise-like object corresponds to theshiny:sessioninitialized
JavaScript event, but is easier to use because it can be used both before and after the events have occurred.
Can you update your example to take advantage of this new property?
ChatGPT
Certainly! Here’s the updated example that uses the Shiny.initializedPromise
to handle the initialization of the session. This makes sure that the local storage value is set after the Shiny session has been properly initialized.
Updated Shiny App Example
library(shiny)
library(bslib)
<- fluidPage(
ui theme = bs_theme(bootswatch = "flatly"),
$head(
tags$script(HTML(
tags"
// Store a variable in local storage when the user inputs a value
Shiny.addCustomMessageHandler('storeValue', function(message) {
localStorage.setItem('storedValue', message.value);
});
// Retrieve the stored value from local storage using initializedPromise
Shiny.initializedPromise.then(function() {
var storedValue = localStorage.getItem('storedValue');
if (storedValue !== null) {
Shiny.setInputValue('storedValue', storedValue);
}
});
"
))
),titlePanel("Shiny Local Storage Example"),
sidebarLayout(
sidebarPanel(
textInput("inputText", "Enter some text:", value = ""),
actionButton("saveBtn", "Save to Local Storage")
),mainPanel(
textOutput("outputText")
)
)
)
<- function(input, output, session) {
server observeEvent(input$saveBtn, {
$sendCustomMessage("storeValue", list(value = input$inputText))
session
})
observeEvent(input$storedValue, {
updateTextInput(session, "inputText", value = input$storedValue)
})
$outputText <- renderText({
outputpaste("Stored value is:", input$inputText)
})
}
shinyApp(ui = ui, server = server)
JavaScript Explanation with Shiny.initializedPromise
Storing the Value:
- The JavaScript code listens for a custom message (
storeValue
) from the Shiny server. - When the message is received, it stores the value in local storage using
localStorage.setItem
.
- The JavaScript code listens for a custom message (
Retrieving the Value:
- Instead of directly listening to the
DOMContentLoaded
event, the code now usesShiny.initializedPromise
. Shiny.initializedPromise
is a Promise-like object that can be awaited or chained with.then()
.- When the Shiny session is initialized, the
then
function is executed, retrieving the stored value from local storage and setting it to a Shiny input (storedValue
) usingShiny.setInputValue
.
- Instead of directly listening to the
This updated approach ensures that the value from local storage is set only after the Shiny session has been fully initialized, improving the reliability of your app.
Prompt
Thanks for your help!
ChatGPT
You’re welcome! If you have any more questions or need further assistance, feel free to ask. Enjoy the rest of your workshop at posit::conf(2024)!