Dans l’article précédent nous avons vu les mécanismes de transfert de données entre l’application Shiny et ses modules.
Maintenant que les modules n’ont (presque plus) de secrets pour vous ; peut-être êtes-vous intéressé pour utiliser un même module plusieurs fois sans pour autant coder chaque appel ?
Dans cet article, nous verrons comment appeler dynamiquement un module et gérer ses outputs server et/ou UI avec 2 exemples :
- Récupérer l’
UId’un module apellé dynamiquement. - Récupérer l’
UI&serverd’un module appelé dynamiquement.
Si vous souhaitez jouer les exemples en local
Tous les codes utilisés ici sont disponibles sur Github ardata-fr/Shiny-Modules-Tutorials.
Ce dépôt est un package R dont les modules sont les fonctions exportées. Les applications Shiny sont dans le dossier inst.
Installer le package et lancer localement les applications :
# install.packages("remotes")
remotes::install_github("ardata-fr/Shiny-Modules-Tutorials")
library(shinyModulesTuto)
# Lister les applications disponibles
listEx()
# Lancer la 1ere application
runEx(listEx()[1])
Exemple 1 : Récupérer seulement l’output UI
Comme vous le savez, un module est composé de 2 fonctions. L’interface UI & la logique server.
Dans cet exemple, la logique server ne retourne rien. Nous avons simplement à gérer les sorties UI.
https://ardata.shinyapps.io/dynamic-call/ ou bien lancer la commande :
# Lancer localement l'application exemple
runEx("dynamic-call")
NB : Dans cet exemple, chaque sortie UI est shinyWidgets::panel.
Application demo
Initialiser rv$all_ui
La reactive rv est initialisée comme ci-dessous :
rv <- reactiveValues(all_ui = list())
Appel dynamique au travers d’un observeEvent
A chaque chargement d’un dataset (cf : incrémentation de data_mod1$trigger), l’observeEvent :
- Exécute la partie
serverlogique du module
callModule(
module = data_info,
id = data_mod1$trigger,
data = data_mod1$data,
data_name = data_mod1$data_name
)
- Récupére la sortie
UIdans la reactiverv$all_ui
rv$all_ui[[data_mod1$trigger]] <- data_infoUI(id = data_mod1$trigger)
Agencement des éléments UI
Dans cet exemple, chaque sortie UI est un shinyWidgets::panel, ainsi on peut les utiliser dans un tagList :
output$all_results <- renderUI({
tagList(rv$all_ui)
})
Exemple 2 : Récupérer les sorties UI & server
Est-ce que vous vous souvenez de l’application whole-app dans l’article précédent ?
Elle est encore disponible en ligne ou vous pouvez la lancer localement :
# Lancer localement l'application exemple
runEx("whole-app")
Pour cet exemple, j’ai créé le module merge_modules qui contient les modules utilisés dans whole-app sauf load_data.
L’objectif est de faire une application contenant le module load_data pour envoyer les données vers le “super-module” merge_modules.
Ce “super-module” merge_modules retourne les parties UI de tous les modules sous-jacents. Sa partie server renvoie une reactiveValues contenant le nom ainsi que le nombre de fonctions appliquées sur chaque jeu de données chargé.
L’application est disponible en ligne https://ardata.shinyapps.io/dynamic-call-whole-app/ ou bien vous pouvez la lancer localement :
# Lancer localement l'application exemple
runEx("dynamic-call-whole-app")
NB : L’application est organisée avec un tabsetPanel, chaque sortie de merge_modules est ajoutée au travers d’un nouveau tabPanel. De plus, chaque tabPanel contient un bouton de fermeture.
Application demo

Initialisation des variables
trick <- reactiveVal(0)
res <- list()
obs_close <- list()
- La
reactiveValtrickest un entier qui s’incrémente à chaque appel du modulemerge_modules. Elle est ensuite utilisée commeidpourtabPanelet pour les noms d’éléments de la listeres. - La liste
rescontient les sortiesserverde chaque appel au modulemerge_modules. - La liste
obs_closecontient lesobserversqui se déclenchent pour la fermeture destabPanel.
Appel dynamique au travers d’un observeEvent
A chaque chargement de dataset (cf : incrémentation de data_mod1$trigger), l’observeEvent :
- Exécute la partie
serverlogique du module et stocke le résultat dans la listeres.
res[[paste(id)]] <<- callModule(
module = merge_modules,
id = id,
data = data,
name = name
)
- Récupère la sortie
UIet crée directement untabPanel(via la fonctionappendTab) :
appendTab(
inputId = "all_tabs",
tabPanel(
title = tabTitle(name, id),
value = id,
tags$br(),
merge_modulesUI(id = id)
),
select = TRUE
)
- Ajoute un
observerdans la listeobs_closepour déclencher la fermeture dutabPanel:
obs_close[[paste(id)]] <<- observe({
shinyjs::onclick(id = paste0("close", id), closeTab(id = id))
})
- Incrémente la
reactiveValuetrick
trick(trick() + 1)
NB : L’incrémentation de trick délenche la mise à jour du renderUI ui_summary.
La
reactiveValtrickest indispensable pour mettre à jourui_summarycar la listeresn’est pas reactive.
Utiliser les sorties server dans l’application
La liste res peut être utilisée n’importe où dans l’application. Cependant, il faut penser à référencer la reactiveVal trick afin que le contexte reactif se mette à jour lorsque res est modifié.
# Summary of all opened tabs
output$ui_summary <- renderUI({
# Reference trick to update reactive context
fool <- trick()
zz <- lapply(res, reactiveValuesToList)
if (length(zz) == 0) {
content <- div(class = "warn ", "No variable loaded")
} else {
# Use output of module merge_modules :
# - name
# - nb_funs
content <- tags$ul(
lapply(zz, function(x) {
tags$li(paste(x$name, ":", x$nb_funs))
})
)
}
tagList(content)
})
Bonus : Fermer un tabPanel
Dans cet exemple, on peut “supprimer” l’appel à un module. Nous devons défaire les étapes réalisées au chapitre précédent :
- Supprimer le
tabPanelcorrespondant (UIpart). - Supprimer l’élément correspondant dans la liste
res(Serverpart).
Ces 2 étapes sont réalisées dans la fonction closeTab décrite ci-dessous. Cette fonction est lancée dans l’observer créé dynamiquement et situé dans obs_close :
closeTab <- function(id) {
# Remove tab from UI
removeTab(inputId = "all_tabs", target = paste(id))
# Remove related element from list
res[[paste(id)]] <<- NULL
# Increase trick to refresh output$ui_summary
trick(trick() + 1)
}
Le bouton de fermeture du tabPanel est créé avec la fonction ci-dessous :
# Function to add a cross after tabPanel title
tabTitle <- function(name, id) {
tags$span(
name, HTML(" "),
tags$span(
id = paste0("close", id),
class = "close",
HTML("×")
)
)
}

Conclusion
L’appel dynamique à un module est très pratique lorsque celui-ci :
- Peut être exécuté un nombre de fois indéfini.
- Executé à partir d’une action utilisateur.
L’appel se fait ensuite dans un observeEvent ou bien un observe puis :
Si on a besoin de la sortie
serveralors la stocker comme nouvel élément d’une liste.Pour la sortie
UIdeux solutions :- Stocker la sortie
UIdans unereactiveValues(cf exemple 1). - Utiliser directement la sortie
UIdans l’observer(cf exemple 2).
- Stocker la sortie
Etre le maître des modules Shiny
Au travers de ces 3 articles, nous avons vu :
- Pourquoi utiliser les modules Shiny ? : Voici quelques cas où ils vous apporteront une précieuse aide.
- Transfert de reactive : Description des mécanismes de transfert de données entre l’application Shiny et ses modules.
- Appel dynamique de modules : Gérer l’appel dynamique aux modules.
J’espère que ces articles vous seront d’une grande aide pour que vous puissiez prendre un max de plaisir à développer vos applications Shiny !
Suivez nous: - Sites recommandés: R-bloggers R weekly Twitter #rstats Jobs for R-users