Reputation: 18561
I am trying to adapt this SO answer regarding how to auto-resize a textarea input via javascript for shiny R. Ideally, I want to avoid helper packages such as shinyJS.
First I tried a pure javascript implementation in which I load the javascript as is into the app (approach 1). Then I tried triggering the javascript function from an observeEvent within shiny (approach 2).
Both approaches are not working. It seems like I am missing something.
Approach 1:
library(shiny)
jsCode1 <- "
var observe;
if (window.attachEvent) {
observe = function (element, event, handler) {
element.attachEvent('on'+event, handler);
};
}
else {
observe = function (element, event, handler) {
element.addEventListener(event, handler, false);
};
}
function init () {
var text = document.getElementById('text');
function resize () {
text.style.height = 'auto';
text.style.height = text.scrollHeight+'px';
}
/* 0-timeout to get the already changed text */
function delayedResize () {
window.setTimeout(resize, 0);
}
observe(text, 'change', resize);
observe(text, 'cut', delayedResize);
observe(text, 'paste', delayedResize);
observe(text, 'drop', delayedResize);
observe(text, 'keydown', delayedResize);
text.focus();
text.select();
resize();
}
init();
"
shinyApp(ui =
fluidPage(
tags$script(jsCode1),
tags$head(
tags$style("
textarea {
border: 0 none white;
overflow: hidden;
padding: 0;
outline: none;
background-color: #D0D0D0;
}
"
)
),
shiny::tagAppendAttributes(
textAreaInput(inputId = "text",
label = "Enter text here",
placeholder = "insert your text here",
width = "100%"),
style = "width: 100%;")
),
server = function(input, output, session) {
}
)
Approach 2:
library(shiny)
jsCode2 <- "
Shiny.addCustomMessageHandler('handler1', init);
function init (el) {
var text = document.getElementById(el);
function resize () {
text.style.height = 'auto';
text.style.height = text.scrollHeight+'px';
}
/* 0-timeout to get the already changed text */
function delayedResize () {
window.setTimeout(resize, 0);
}
observe(text, 'change', resize);
observe(text, 'cut', delayedResize);
observe(text, 'paste', delayedResize);
observe(text, 'drop', delayedResize);
observe(text, 'keydown', delayedResize);
text.focus();
text.select();
resize();
}"
shinyApp(ui =
fluidPage(
tags$script(jsCode2),
tags$head(
tags$style("
textarea {
border: 0 none white;
overflow: hidden;
padding: 0;
outline: none;
background-color: #D0D0D0;
}
"
)
),
shiny::tagAppendAttributes(
textAreaInput(inputId = "text",
label = "Enter text here",
placeholder = "insert your text here",
width = "100%"),
style = "width: 100%;")
),
server = function(input, output, session) {
observeEvent(input$text,{
session$sendCustomMessage("handler1", message = "text")
})
}
)
Upvotes: 3
Views: 846
Reputation: 669
A bit late, but this worked for me to dynamically expand the textArea vertically while typing:
library(shiny)
ui <- fluidPage(
tags$head(
tags$style(
HTML("
textArea {
overflow: hidden;
resize: none;
}
")
),
tags$script(
HTML('
$(document).on("input", "#text", function() {
this.style.height = "auto";
this.style.height = (this.scrollHeight) + "px";
});
')
)
),
textAreaInput("text", "", placeholder = "Enter your text", rows = 1, width = "200px")
)
server <- function(input, output, session) {
observeEvent(input$text,
print(input$text)
)
}
shinyApp(ui, server)
Upvotes: 0
Reputation: 17689
It could be the case that you tried to attach the resizing event to the textinput()
before the latter was added to the DOM.
I added an event listener that waits until the DOM is loaded before the resizing event is attached.
document.addEventListener('DOMContentLoaded', function(event) {...})
shinyjs
will do that automatically for you. Adding the event listener above, you can make it work without using shinyjs
.
Javascript code:
jsCode <- "document.addEventListener('DOMContentLoaded', function(event) {
var observe;
if (window.attachEvent) {
observe = function (element, event, handler) {
element.attachEvent('on'+event, handler);
};
}
else {
observe = function (element, event, handler) {
element.addEventListener(event, handler, false);
};
}
function init () {
var text = document.getElementById('text');
function resize () {
text.style.height = 'auto';
text.style.height = text.scrollHeight+'px';
}
/* 0-timeout to get the already changed text */
function delayedResize () {
window.setTimeout(resize, 0);
}
observe(text, 'change', resize);
observe(text, 'cut', delayedResize);
observe(text, 'paste', delayedResize);
observe(text, 'drop', delayedResize);
observe(text, 'keydown', delayedResize);
text.focus();
text.select();
resize();
};init()
})
"
The app:
library(shiny)
ui <- fluidPage(
shiny::tags$script(jsCode),
textAreaInput(inputId = "text", label = "a", value = "b")
)
server <- function(input, output, session) {
}
shinyApp(ui, server)
Upvotes: 5