I'm trying modularising code. I am trying to generate a viable number of categories, with a variable number of rows. Each row has txtOutputs and actionButtons
This first example with actionLinks for the categories works (see https://ikusei.shinyapps.io/IkuseiBoK/. Trying doing the same with tabPanels instead of actionLinks is doing my head in (see code below).
Any help would be appreciated
WORKING CODE
#
#This is a Shiny web application. You can run the application by clicking
#the 'Run App' button above.
#
#Find out more about building applications with Shiny here:
#
#http://shiny.rstudio.com/
#
library('shiny')
library("htmltools")
library("vembedr")
library("RSQLite")
library("shinyjs")
library("V8")
jsResetCode <- "shinyjs.reset = function() {history.go(0)}" #Define the js method that resets the page
#open db
db <- dbConnect(SQLite(),"data/BoK.db")
#Initial category id
catid <- 1
#######MODULES
gen_tabsUI <- function(id, users_cats, i) {
ns <- NS(id)
column(2, tags$span(actionLink(ns("lnkCat"),paste0(users_cats[i,2])) ),align="center")
}
gen_tabs <- function(input, output, session, users_cats, i) {
observeEvent(input$lnkCat, {
catid <<- users_cats[i, 4]
js$reset()
})
}
#UI part of module gen_rows
#generate the fluidRow
gen_rowsUI <- function(id, users_drills, no_cats, users_cats) {
ns <- NS(id)
#generate the fluidRow
fluidPage(
fluidRow(
#drill title
column(12, tags$p(textOutput(ns("txtTitle"))))
),
fluidRow(
#drill weighting
column(6,
#drill reps
tags$p("Completed ",
actionButton(ns("btnDec"), label=NULL, icon("minus") ,36),
textOutput(ns("txtReps"), inline = TRUE),
actionButton(ns("btnInc"), label=NULL, icon("plus") ,36),
"Times"),
align = "left"),
column(6, tags$p("Weighting is",
actionButton(ns("btnDecW"), label=NULL, icon("minus") ,36),
textOutput(ns("txtWeight"), inline = TRUE),
actionButton(ns("btnIncW"), label=NULL, icon("plus") ,36),
align = "right")
)
),
hr()
)
}
#Server part of module gen_rows
gen_rows <- function(input, output, session, users_drills, indx, no_cats, users_cats) {
reps <- users_drills[indx, 1]
title <- users_drills[indx, 2]
weight <- users_drills[indx, 3]
prio <- users_drills[indx, 4]
drill_order <- users_drills[indx, 5]
output$txtReps <- renderText(reps)
output$txtTitle <- renderText(paste(title, prio, sep = " - "))
output$txtWeight <- renderText(weight)
observeEvent(input$btnInc,{
#requery database so datframe ('user_drills') has latest data
qry_users_drills <- dbSendQuery(db, paste0("SELECT reps, title, weight, prio, [order], catid
FROM `drills` INNER JOIN users_drills
ON drills.id = users_drills.drillid
WHERE userid = 1 AND catid = ", catid ," ORDER BY [order]"))
users_drills <- dbFetch(qry_users_drills, n = -1)
dbClearResult(qry_users_drills)
reps <- users_drills[indx, 1]
title <- users_drills[indx, 2]
weight <- users_drills[indx, 3]
prio <- users_drills[indx, 4]
drill_order <- users_drills[indx, 5]
#add 1 to the reps
reps <- reps + 1
#recalculate priority
prio <- ((weight)/(reps + 1)) * 1000000
#render reps and title
output$txtReps <- renderText(reps)
output$txtTitle <- renderText(paste(title, prio, sep = " - "))
temp <- drill_order
#update database
qry_string <- paste0("UPDATE users_drills SET reps = ", reps, ", prio = ", prio, "
WHERE userid = 1 AND [order] = ", drill_order)
qry_users_drills <- dbSendQuery(db, qry_string)
dbClearResult(qry_users_drills)
})
observeEvent(input$btnDec,{
#requery database so datframe ('user_drills') has latest data
qry_users_drills <- dbSendQuery(db, paste0("SELECT reps, title, weight, prio, [order], catid
FROM `drills` INNER JOIN users_drills
ON drills.id = users_drills.drillid
WHERE userid = 1 AND catid = ", catid ," ORDER BY [order]"))
users_drills <- dbFetch(qry_users_drills, n = -1)
dbClearResult(qry_users_drills)
reps <- users_drills[indx, 1]
title <- users_drills[indx, 2]
weight <- users_drills[indx, 3]
prio <- users_drills[indx, 4]
drill_order <- users_drills[indx, 5]
if (reps > 0){
reps <- reps - 1
}
prio <- ((weight)/(reps + 1)) * 1000000
#users_drills[indx, 2] <- reps
#users_drills[indx, 5] <- prio
output$txtReps <- renderText(reps)
output$txtTitle <- renderText(paste(title, prio, sep = " - "))
#update database
qry_string <- paste0("UPDATE users_drills SET reps = ", reps, ", prio = ", prio, "
WHERE userid = 1 AND [order] = ", drill_order)
qry_users_drills <- dbSendQuery(db, qry_string)
dbClearResult(qry_users_drills)
})
observeEvent(input$btnIncW,{
#requery database so datframe ('user_drills') has latest data
qry_users_drills <- dbSendQuery(db, paste0("SELECT reps, title, weight, prio, [order], catid
FROM `drills` INNER JOIN users_drills
ON drills.id = users_drills.drillid
WHERE userid = 1 AND catid = ", catid ," ORDER BY [order]"))
users_drills <- dbFetch(qry_users_drills, n = -1)
dbClearResult(qry_users_drills)
reps <- users_drills[indx, 1]
title <- users_drills[indx, 2]
weight <- users_drills[indx, 3]
prio <- users_drills[indx, 4]
drill_order <- users_drills[indx, 5]
if (weight >= 5) {
weight = 5
} else {
weight <- weight + 1
}
prio <- ((weight)/(reps + 1)) * 1000000
#users_drills[indx, 4] <- weight
#users_drills[indx, 5] <- prio
output$txtWeight <- renderText(weight)
output$txtTitle <- renderText(paste(title, prio, sep = " - "))
#update database
qry_string <- paste0("UPDATE users_drills SET weight = ", weight, ", prio = ", prio, "
WHERE userid = 1 AND [order] = ", drill_order)
qry_users_drills <- dbSendQuery(db, qry_string)
dbClearResult(qry_users_drills)
})
observeEvent(input$btnDecW,{
#requery database so datframe ('user_drills') has latest data
qry_users_drills <- dbSendQuery(db, paste0("SELECT reps, title, weight, prio, [order], catid
FROM `drills` INNER JOIN users_drills
ON drills.id = users_drills.drillid
WHERE userid = 1 AND catid = ", catid ," ORDER BY [order]"))
users_drills <- dbFetch(qry_users_drills, n = -1)
dbClearResult(qry_users_drills)
reps <- users_drills[indx, 1]
title <- users_drills[indx, 2]
weight <- users_drills[indx, 3]
prio <- users_drills[indx, 4]
drill_order <- users_drills[indx, 5]
if (weight <= 0) {
weight = 0
} else {
weight <- weight - 1
}
prio <- ((weight)/(reps + 1)) * 1000000
#users_drills[indx, 4] <- weight
#users_drills[indx, 5] <- prio
output$txtWeight <- renderText(weight)
output$txtTitle <- renderText(paste(title, prio, sep = " - "))
#update database
qry_string <- paste0("UPDATE users_drills SET weight = ", weight, ", prio = ", prio, "
WHERE userid = 1 AND [order] = ", drill_order)
qry_users_drills <- dbSendQuery(db, qry_string)
dbClearResult(qry_users_drills)
})
}
#Define UI for Drill Browser
ui <- fluidPage(
useShinyjs(),
extendShinyjs(text = jsResetCode), #Add the js code to the page
#Application title
titlePanel("Ikusei Body of Knowledge"),
#Header row
fluidRow(
column(6, tags$h4("Exercises")),
column(6, actionButton("btnRefresh", "Refresh", NULL, width = 96), align = "right")
),
fluidRow(
uiOutput("Cats")
),
#Generate list of drills dynamically
uiOutput("listofDrills")
)
#Define server logic
server <- function(input, output) {
#obtain list of drills and put in to a data frame
qry_users_drills <- dbSendQuery(db,"SELECT drillid, reps, title, weight, prio, [order], catid
FROM `drills` INNER JOIN users_drills
ON drills.id = users_drills.drillid
WHERE userid = 1 ORDER BY prio DESC, reps DESC")
#data frame 'users_drills'
users_drills <- dbFetch(qry_users_drills, n = -1)
dbClearResult(qry_users_drills)
#obtain no of drills (rows)
drills_no <- nrow(users_drills)
for(i in 1:drills_no) {
reps <- users_drills[i, 2]
weight <- users_drills[i, 4]
prio <- users_drills[i, 5]
prio <- ((weight)/(reps + 1)) * 1000000
qry_string <- paste0("UPDATE users_drills SET [order] = ", i, ", [prio] = ", prio,
" WHERE userid = 1 AND drillid = ", users_drills[i, 1])
qry_users_drills <- dbSendQuery(db, qry_string)
dbClearResult(qry_users_drills)
}
#requery database so datframe ('user_cats') has latest data
qry_users_cats <- dbSendQuery(db, "SELECT title, display, [order], id FROM cats INNER JOIN users_cats
ON cats.id = users_cats.catid WHERE userid = 1 ORDER BY [order]")
users_cats <- dbFetch(qry_users_cats, n = -1)
dbClearResult(qry_users_cats)
#obtain number of categories
no_cats <- nrow(users_cats)
#Generate a tab for every category in the "users_drills" table
observeEvent(no_cats, {
output$Cats <- renderUI({
#for each cat create a tab
lapply (1:no_cats, function(i) {
gen_tabsUI(i, users_cats, i)
})
})
lapply(1:no_cats, function(i) {
callModule(gen_tabs, i, users_cats, i)
})
})
#requery database so datframe ('user_drills') has latest data
qry_users_drills <- dbSendQuery(db, paste0("SELECT reps, title, weight, prio, [order], catid
FROM `drills` INNER JOIN users_drills
ON drills.id = users_drills.drillid
WHERE userid = 1 AND catid = ", users_cats[catid, 3] ," ORDER BY [order]"))
users_drills <- dbFetch(qry_users_drills, n = -1)
dbClearResult(qry_users_drills)
#obtain no of drills (rows)
no_drills <- nrow(users_drills)
#Generate a row for every drill in the "users_drills" table
observeEvent(no_drills, {
output$listofDrills <- renderUI({
if (no_drills > 0) {
#for each drill create fluidRow
lapply (1:no_drills, function(i) {
gen_rowsUI(i, users_drills, no_cats, users_cats)
})
}
})
lapply(1:no_drills, function(i) {
callModule(gen_rows, i, users_drills, i, no_cats, users_cats)
})
})
observeEvent(input$btnRefresh, {
js$reset()
})
}
#Run the application
shinyApp(ui = ui, server = server)
BAD CODE
#
# This is a Shiny web application. You can run the application by clicking
# the 'Run App' button above.
#
# Find out more about building applications with Shiny here:
#
# http://shiny.rstudio.com/
#
library('shiny')
library("htmltools")
library("vembedr")
library("RSQLite")
library("shinyjs")
library("V8")
jsResetCode <- "shinyjs.reset = function() {history.go(0)}" # Define the js method that resets the page
#open db
db <- dbConnect(SQLite(),"data/BoK.db")
# Initial category id
catid <- 1
users_drills <- NULL
####### MODULES
# UI part of module gen_rows
gen_rowsUI <- function(id) {
ns <- NS(id)
div(
# drill title
column(12,
div(tags$p(textOutput(ns("txtTitle"))))
),
# drill weighting
column(6,
# drill reps
tags$p("Completed ",
actionButton(ns("btnDec"), label=NULL, icon("minus") ,36),
textOutput(ns("txtReps"), inline = TRUE),
actionButton(ns("btnInc"), label=NULL, icon("plus") ,36),
"Times"),
align = "left"),
column(6,
# drill weighting
tags$p("Weighting is",
actionButton(ns("btnDecW"), label=NULL, icon("minus") ,36),
textOutput(ns("txtWeight"), inline = TRUE),
actionButton(ns("btnIncW"), label=NULL, icon("plus") ,36)),
align = "right"),
hr()
)
}
# Server part of module gen_rows
gen_rows <- function(input, output, session, users_drills, indx, no_cats, users_cats) {
reps <- users_drills[indx, 1]
title <- users_drills[indx, 2]
weight <- users_drills[indx, 3]
prio <- users_drills[indx, 4]
drill_order <- users_drills[indx, 5]
output$txtReps <- renderText(reps)
output$txtTitle <- renderText(paste(title))# , prio, sep = " - "))
output$txtWeight <- renderText(weight)
observeEvent(input$btnInc,{
#requery database so datframe ('user_drills') has latest data
qry_users_drills <- dbSendQuery(db, paste0("SELECT reps, title, weight, prio, [order], catid
FROM `drills` INNER JOIN users_drills
ON drills.id = users_drills.drillid
WHERE userid = 1 AND catid = ", catid ," ORDER BY [order]"))
users_drills <<- dbFetch(qry_users_drills, n = -1)
dbClearResult(qry_users_drills)
reps <- users_drills[indx, 1]
title <- users_drills[indx, 2]
weight <- users_drills[indx, 3]
prio <- users_drills[indx, 4]
drill_order <- users_drills[indx, 5]
# add 1 to the reps
reps <- reps + 1
# recalculate priority
prio <- ((5 - weight)/(reps + 1)) * 1000000
# render reps and title
output$txtReps <- renderText(reps)
output$txtTitle <- renderText(paste(title))#, prio, sep = " - "))
temp <- drill_order
#update database
qry_string <- paste0("UPDATE users_drills SET reps = ", reps, ", prio = ", prio, "
WHERE userid = 1 AND [order] = ", drill_order)
qry_users_drills <- dbSendQuery(db, qry_string)
dbClearResult(qry_users_drills)
})
observeEvent(input$btnDec,{
#requery database so datframe ('user_drills') has latest data
qry_users_drills <- dbSendQuery(db, paste0("SELECT reps, title, weight, prio, [order], catid
FROM `drills` INNER JOIN users_drills
ON drills.id = users_drills.drillid
WHERE userid = 1 AND catid = ", catid ," ORDER BY [order]"))
users_drills <<- dbFetch(qry_users_drills, n = -1)
dbClearResult(qry_users_drills)
reps <- users_drills[indx, 1]
title <- users_drills[indx, 2]
weight <- users_drills[indx, 3]
prio <- users_drills[indx, 4]
drill_order <- users_drills[indx, 5]
if (reps > 0){
reps <- reps - 1
}
prio <- ((5 - weight)/(reps + 1)) * 1000000
# users_drills[indx, 2] <- reps
# users_drills[indx, 5] <- prio
output$txtReps <- renderText(reps)
output$txtTitle <- renderText(paste(title))#, prio, sep = " - "))
#update database
qry_string <- paste0("UPDATE users_drills SET reps = ", reps, ", prio = ", prio, "
WHERE userid = 1 AND [order] = ", drill_order)
qry_users_drills <- dbSendQuery(db, qry_string)
dbClearResult(qry_users_drills)
})
observeEvent(input$btnIncW,{
#requery database so datframe ('user_drills') has latest data
qry_users_drills <- dbSendQuery(db, paste0("SELECT reps, title, weight, prio, [order], catid
FROM `drills` INNER JOIN users_drills
ON drills.id = users_drills.drillid
WHERE userid = 1 AND catid = ", catid ," ORDER BY [order]"))
users_drills <<- dbFetch(qry_users_drills, n = -1)
dbClearResult(qry_users_drills)
reps <- users_drills[indx, 1]
title <- users_drills[indx, 2]
weight <- users_drills[indx, 3]
prio <- users_drills[indx, 4]
drill_order <- users_drills[indx, 5]
if (weight >= 5) {
weight = 5
} else {
weight <- weight + 1
}
prio <- ((5 - weight)/(reps + 1)) * 1000000
# users_drills[indx, 4] <- weight
# users_drills[indx, 5] <- prio
output$txtWeight <- renderText(weight)
output$txtTitle <- renderText(paste(title))#, prio, sep = " - "))
#update database
qry_string <- paste0("UPDATE users_drills SET weight = ", weight, ", prio = ", prio, "
WHERE userid = 1 AND [order] = ", drill_order)
qry_users_drills <- dbSendQuery(db, qry_string)
dbClearResult(qry_users_drills)
})
observeEvent(input$btnDecW,{
#requery database so datframe ('user_drills') has latest data
qry_users_drills <- dbSendQuery(db, paste0("SELECT reps, title, weight, prio, [order], catid
FROM `drills` INNER JOIN users_drills
ON drills.id = users_drills.drillid
WHERE userid = 1 AND catid = ", catid ," ORDER BY [order]"))
users_drills <<- dbFetch(qry_users_drills, n = -1)
dbClearResult(qry_users_drills)
reps <- users_drills[indx, 1]
title <- users_drills[indx, 2]
weight <- users_drills[indx, 3]
prio <- users_drills[indx, 4]
drill_order <- users_drills[indx, 5]
if (weight <= 0) {
weight = 0
} else {
weight <- weight - 1
}
prio <- ((5 - weight)/(reps + 1)) * 1000000
# users_drills[indx, 4] <- weight
# users_drills[indx, 5] <- prio
output$txtWeight <- renderText(weight)
output$txtTitle <- renderText(paste(title))#, prio, sep = " - "))
#update database
qry_string <- paste0("UPDATE users_drills SET weight = ", weight, ", prio = ", prio, "
WHERE userid = 1 AND [order] = ", drill_order)
qry_users_drills <- dbSendQuery(db, qry_string)
dbClearResult(qry_users_drills)
})
}
# Define UI for Drill Browser
ui <- fluidPage(
useShinyjs(),
extendShinyjs(text = jsResetCode), # Add the js code to the page
# Application title
titlePanel("Ikusei Body of Knowledge"),
# Header row
fluidRow(
column(6, tags$h4("Exercises")),
# column(3, actionButton("run", "Run Analysis", icon("paper-plane"),
# style="color: #fff; background-color: #337ab7; border-color: #2e6da4")),
column(3, actionButton("btnRefresh", "Refresh", NULL, width = 96), align = "right", offset = 3)
),
tabsetPanel(
tabPanel("default"),
# tabPanel("default2"),
# # Generate list of drills dynamically
# div(uiOutput("listofDrills")),
id ="Cats", selected = NULL, type = "pills")
)
# Define server logic
server <- function(input, output) {
# obtain list of drills and put in to a data frame
qry_users_drills <- dbSendQuery(db,"SELECT drillid, reps, title, weight, prio, [order], catid
FROM `drills` INNER JOIN users_drills
ON drills.id = users_drills.drillid
WHERE userid = 1 ORDER BY prio ASC, reps DESC")
# data frame 'users_drills'
users_drills <<- dbFetch(qry_users_drills, n = -1)
dbClearResult(qry_users_drills)
#obtain no of drills (rows)
drills_no <- nrow(users_drills)
for(i in 1:drills_no) {
reps <- users_drills[i, 2]
weight <- users_drills[i, 4]
prio <- users_drills[i, 5]
prio <- ((5 - weight)/(reps + 1)) * 1000000
qry_string <- paste0("UPDATE users_drills SET [order] = ", i, ", [prio] = ", prio,
" WHERE userid = 1 AND drillid = ", users_drills[i, 1])
qry_users_drills <- dbSendQuery(db, qry_string)
dbClearResult(qry_users_drills)
}
#requery database so datframe ('user_cats') has latest data
qry_users_cats <- dbSendQuery(db, "SELECT title, display, [order], id FROM cats INNER JOIN users_cats
ON cats.id = users_cats.catid WHERE userid = 1 ORDER BY [order]")
users_cats <- dbFetch(qry_users_cats, n = -1)
dbClearResult(qry_users_cats)
# obtain number of categories
no_cats <- nrow(users_cats)
for (i in 1:no_cats) {
#requery database so datframe ('user_drills') has latest data
qry_users_drills <- dbSendQuery(db, paste0("SELECT reps, title, weight, prio, [order], catid
FROM `drills` INNER JOIN users_drills
ON drills.id = users_drills.drillid
WHERE userid = 1 AND catid = ", users_cats[i, 4] ," ORDER BY [order]"))
users_drills <<- dbFetch(qry_users_drills, n = -1)
dbClearResult(qry_users_drills)
#obtain no of drills (rows)
no_drills <- nrow(users_drills)
a <- users_cats[i, 3]
# output$listofDrills <- renderUI({
appendTab(inputId = "Cats",
tabPanel(users_cats[i,2],
# if (no_drills > 0) {
# # for each drill create fluidRow
lapply (1:(no_drills/5), function(d) {
gen_rowsUI(d)
}),
# }
b <- i,
lapply(1:no_drills, function(d) {
callModule(gen_rows, d, users_drills, d, no_cats, users_cats)
})
, paste0(i)
)
)
}
# # Generate a tab for every category in the "users_drills" table
# observeEvent(no_cats, {
#
# output$Cats <- renderUI({
# # for each cat create a tab
# lapply (1:no_cats, function(i) {
# gen_tabsUI(i, users_cats, i)
# })
# })
#
# lapply(1:no_cats, function(i) {
#
# callModule(gen_tabs, i, users_cats, i)
# })
# })
observeEvent(input$btnRefresh, {
js$reset()
})
}
# Run the application
shinyApp(ui = ui, server = server)