Reputation: 314
I am creating a R shiny app that accepts a csv file as input and depends upon the results I can use the buttons 'split columns' 'delete Rows' etc...
However, I added javascript(callback) for editing column names and called the 'callback' variable in the server function; it works fine, but when I edit column names, the select column' field is not updated automatically, however, when I do so for other functions like 'split column' the 'select column' field is updated.
could someone help me to fix this issue?
I've already added a server method for changing the column name.:
#Server functionf for editing the column names, javascript callback
output[["table1"]] <- renderDT({
datatable(rv$data, callback = JS(callback))
}, server = FALSE)
csv data
ID Type Range
21 A1 B1 100
22 C1 D1 200
23 E1 F1 300
app.R EDITED:
library(shiny)
library(reshape2)
library(DT)
library(tibble)
#Javascript callback for editing the column names
callback <- c(
"table.on('dblclick.dt', 'thead th', function(e) {",
" var $th = $(this);",
" var index = $th.index();",
" var colname = $th.text(), newcolname = colname;",
" var $input = $('<input type=\"text\">')",
" $input.val(colname);",
" $th.empty().append($input);",
" $input.on('blur', function(){",
" newcolname = $input.val();",
" Shiny.setInputValue('newcol', {i: index, name: newcolname});",
" $(table.column(index).header()).text(newcolname);",
" $input.remove();",
" });",
"});"
)
###function for deleting the rows
splitColumn <- function(data, column_name) {
newColNames <- c("Unmerged_type1", "Unmerged_type2")
newCols <- colsplit(data[[column_name]], " ", newColNames)
after_merge <- cbind(data, newCols)
after_merge[[column_name]] <- NULL
after_merge
}
###_______________________________________________
### function for inserting a new column
fillvalues <- function(data, values, columName){
df_fill <- data
vec <- strsplit(values, ",")[[1]]
df_fill <- tibble::add_column(df_fill, newcolumn = vec, .after = columName)
df_fill
}
##function for removing the colum
removecolumn <- function(df, nameofthecolumn){
df[ , -which(names(df) %in% nameofthecolumn)]
}
### use a_splitme.csv for testing this program
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
fileInput("file1", "Choose CSV File", accept = ".csv"),
checkboxInput("header", "Header", TRUE),
actionButton("Splitcolumn", "SplitColumn", class = "btn-warning" ),
uiOutput("selectUI"),
actionButton("replacevalues", label = 'Replace values', class= "btn-Secondary"),
actionButton("removecolumn", "Remove Column"),
actionButton("Undo", 'Undo', style="color: #fff; background-color: #337ab7; border-color: #2e6da4"),
actionButton("deleteRows", "Delete Rows"),
textInput("textbox", label="Input the value to replace:"),
actionButton('downloadbtn', label= 'Download'),
),
mainPanel(
DTOutput("table1")
)
)
)
server <- function(session, input, output) {
rv <- reactiveValues(data = NULL, orig=NULL)
observeEvent(input$file1, {
file <- input$file1
ext <- tools::file_ext(file$datapath)
req(file)
validate(need(ext == "csv", "Please upload a csv file"))
rv$orig <- read.csv(file$datapath, header = input$header)
rv$data <- rv$orig
})
output$selectUI<-renderUI({
req(rv$data)
selectInput(inputId='selectcolumn', label='select column', choices = names(rv$data))
})
observeEvent(input$Splitcolumn, {
rv$data <- splitColumn(rv$data, input$selectcolumn)
})
observeEvent(input$deleteRows,{
if (!is.null(input$table1_rows_selected)) {
rv$data <- rv$data[-as.numeric(input$table1_rows_selected),]
}
})
output$table1 <- renderDT(
rv$data, server = F, editable = T
)
#includes extra column after the 'select column' and replaces the values specified 'Input the value to replace:'
observeEvent(input$replacevalues, {
rv$data <- fillvalues(rv$data, input$textbox, input$selectcolumn)
})
#Removing the specifield column through select column
observeEvent(input$removecolumn, {
rv$data <- removecolumn(rv$data,input$selectcolumn)
})
observeEvent(input$Undo, {
rv$data <- rv$orig
})
#Storing the csv file through download button
observeEvent(input$downloadbtn,{
write.csv(rv$data,'test.csv')
print ('file has been downloaded')
})
observeEvent(input$downloadbtn, {
showModal(modalDialog(
title = "Download Status.",
paste0("csv file has been downloaded",input$downloadbtn,'.'),
easyClose = TRUE,
footer = NULL
))
})
#Server functionf for editing the column names, javascript callback
output[["table1"]] <- renderDT({
datatable(rv$data, callback = JS(callback))
}, server = FALSE)
#datatable(rv$data,options = list(searching=FALSE, pageLength=100))
}
shinyApp(ui, server)
Upvotes: 0
Views: 339
Reputation: 84529
You can send the index of the changed header and its name to Shiny in the blur
listener with Shiny.setInputValue
:
" }).on('blur', function(){",
" $(table.column(index).header()).text(newcolname);",
" $input.remove();",
" Shiny.setInputValue('newcol', {i: index+1, name: newcolname});",
" });",
In this way, in server
you get input[["newcol]]"
, a list with the index i
and the new name name
. Then observe this input and change the column names of rv$data
:
observeEvent(input[["newcol"]], {
i <- input[["newcol"]][["i"]]
names(rv$data)[i] <- input[["newcol"]][["name"]]
})
In fact, the change
listener is useless. You can use this callback:
callback <- c(
"table.on('dblclick.dt', 'thead th', function(e) {",
" var $th = $(this);",
" var index = $th.index();",
" var colname = $th.text(), newcolname = colname;",
" var $input = $('<input type=\"text\">')",
" $input.val(colname);",
" $th.empty().append($input);",
" $input.on('blur', function(){",
" newcolname = $input.val();",
" Shiny.setInputValue('newcol', {i: index, name: newcolname});",
" $(table.column(index).header()).text(newcolname);",
" $input.remove();",
" });",
"});"
)
Upvotes: 1