Problème
Lors de la création dynamique ui-éléments ( shiny.tag
, shiny.tag.list
, ...), je trouve qu'il est souvent difficile de le séparer de ma logique de code et finissent généralement avec un désordre alambiqué de imbriqué tags$div(...)
, mélangé avec des boucles et des instructions conditionnelles. Bien que gênant et laid à regarder, il est également sujet aux erreurs, par exemple lors de la modification de modèles html.
Exemple reproductible
Disons que j'ai la structure de données suivante:
my_data <- list(
container_a = list(
color = "orange",
height = 100,
content = list(
vec_a = c(type = "p", value = "impeach"),
vec_b = c(type = "h1", value = "orange")
)
),
container_b = list(
color = "yellow",
height = 50,
content = list(
vec_a = c(type = "p", value = "tool")
)
)
)
Si je veux maintenant pousser cette structure en ui-tags, je me retrouve généralement avec quelque chose comme:
library(shiny)
my_ui <- tagList(
tags$div(
style = "height: 400px; background-color: lightblue;",
lapply(my_data, function(x){
tags$div(
style = paste0("height: ", x$height, "px; background-color: ", x$color, ";"),
lapply(x$content, function(y){
if (y[["type"]] == "h1") {
tags$h1(y[["value"]])
} else if (y[["type"]] == "p") {
tags$p(y[["value"]])
}
})
)
})
)
)
server <- function(input, output) {}
shinyApp(my_ui, server)
Comme vous pouvez le voir, c'est déjà assez désordonné et toujours rien par rapport à mes vrais exemples.
Solution souhaitée
J'espérais trouver quelque chose de proche d'un moteur de template pour R, qui permettrait de définir des modèles et des données séparément :
# syntax, borrowed from handlebars.js
my_template <- tagList(
tags$div(
style = "height: 400px; background-color: lightblue;",
"{{#each my_data}}",
tags$div(
style = "height: {{this.height}}px; background-color: {{this.color}};",
"{{#each this.content}}",
"{{#if this.content.type.h1}}",
tags$h1("this.content.type.h1.value"),
"{{else}}",
tags$p(("this.content.type.p.value")),
"{{/if}}",
"{{/each}}"
),
"{{/each}}"
)
)
Tentatives précédentes
Tout d'abord, je pensais que cela shiny::htmlTemplate()
pourrait offrir une solution, mais cela ne fonctionnerait qu'avec des fichiers et des chaînes de texte, pas l' shiny.tag
art. J'ai également jeté un coup d'œil à certains r-packages comme whisker
, mais ceux-ci semblent avoir la même limitation et ne prennent pas en charge les balises ou les structures de liste.
Je vous remercie!
la source
www
dossier, puis appliquer les feuilles de style?htmlTemplate()
cela permettrait de conditionner et de boucler ala guidon, moustache, brindille ...Réponses:
J'aime créer des éléments d'interface utilisateur composables et réutilisables à l'aide de fonctions qui produisent des balises HTML (ou
htmltools
balises) Shiny . À partir de votre exemple d'application, j'ai pu identifier un élément "page", puis deux conteneurs de contenu génériques, puis créer des fonctions pour ceux-ci:Et puis je pourrais composer mon interface utilisateur avec quelque chose comme ceci:
Chaque fois que j'ai besoin de modifier le style ou le HTML d'un élément, je vais directement à la fonction qui génère cet élément.
En outre, je viens de souligner les données dans ce cas. Je pense que la structure des données dans votre exemple mélange vraiment les données avec les problèmes d'interface utilisateur (style, balises HTML), ce qui pourrait expliquer une partie de l'altération. Les seules données que je vois sont "orange" comme en-tête et "impeach" / "tool" comme contenu.
Si vous avez des données plus complexes ou avez besoin de composants d'interface utilisateur plus spécifiques, vous pouvez à nouveau utiliser des fonctions comme des blocs de construction:
J'espère que cela pourra aider. Si vous cherchez de meilleurs exemples, vous pouvez consulter le code source derrière les éléments d'entrée et de sortie de Shiny (par exemple
selectInput()
), qui sont essentiellement des fonctions qui crachent des balises HTML. Un moteur de template pourrait également fonctionner, mais il n'y a pas vraiment besoin quand vous avez déjàhtmltools
+ la pleine puissance de R.la source
Peut-être pourriez-vous envisager d'examiner
glue()
etget()
.avoir():
get()
peut transformer des chaînes en variables / objets.Vous pouvez donc raccourcir:
à
(voir l'exemple ci-dessous).
la colle():
glue()
fournit une alternative àpaste0()
. Cela pourrait être plus lisible si vous concentrez beaucoup de chaînes et de variables à une chaîne. Je suppose que cela ressemble également à la syntaxe du résultat souhaité.Au lieu de:
Vous écririez:
Votre exemple se simplifierait pour:
En utilisant:
Alternatives:
Je pense que htmltemplate est une bonne idée, mais un autre problème concerne les espaces blancs indésirables: https://github.com/rstudio/htmltools/issues/19#issuecomment-252957684 .
la source