Problem
Wenn dynamisch ui-Elemente zu schaffen ( shiny.tag
, shiny.tag.list
, ...), finde ich es oft schwierig , es von meiner Code - Logik zu trennen und in der Regel mit einem gewundenen Durcheinander von verschachteltem Endetags$div(...)
, gemischt mit Schleifen und bedingten Anweisungen. Es ist zwar nervig und hässlich anzusehen, aber auch fehleranfällig, z. B. wenn Änderungen an HTML-Vorlagen vorgenommen werden.
Reproduzierbares Beispiel
Angenommen, ich habe die folgende Datenstruktur:
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")
)
)
)
Wenn ich diese Struktur jetzt in UI-Tags verschieben möchte, habe ich normalerweise Folgendes:
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)
Wie Sie sehen können, ist dies bereits ziemlich chaotisch und immer noch nichts im Vergleich zu meinen echten Beispielen.
Gewünschte Lösung
Ich hatte gehofft, etwas in der Nähe einer Vorlagen- Engine für R zu finden, mit dem Vorlagen und Daten separat definiert werden können :
# 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}}"
)
)
Frühere Versuche
Zuerst dachte ich, das shiny::htmlTemplate()
könnte eine Lösung bieten, aber dies würde nur mit Dateien und Textzeichenfolgen funktionieren, nicht mit shiny.tag
s. Ich habe mir auch einige R-Pakete wie Whisker angesehen
, aber diese scheinen die gleiche Einschränkung zu haben und unterstützen keine Tags oder Listenstrukturen.
Vielen Dank!
quelle
www
Ordner speichern und dann die Stylesheets anwenden?htmlTemplate()
würden Bedingungen und Schlaufen ua Lenker, Schnurrbart, Zweig ...Antworten:
Ich mag es, zusammensetzbare und wiederverwendbare UI-Elemente mit Funktionen zu erstellen, die Shiny HTML-Tags (oder
htmltools
Tags) erzeugen . In Ihrer Beispiel-App konnte ich ein "Seiten" -Element und dann zwei generische Inhaltscontainer identifizieren und dann einige Funktionen für diese erstellen:Und dann könnte ich meine Benutzeroberfläche mit so etwas zusammenstellen:
Jedes Mal, wenn ich das Styling oder den HTML-Code eines Elements anpassen muss, gehe ich direkt zu der Funktion, die dieses Element generiert.
Außerdem habe ich in diesem Fall gerade die Daten eingefügt. Ich denke, die Datenstruktur in Ihrem Beispiel mischt Daten wirklich mit UI-Bedenken (Styling, HTML-Tags), was einige der Verschachtelungen erklären könnte. Die einzigen Daten, die ich sehe, sind "orange" als Kopfzeile und "Amtsenthebung" / "Werkzeug" als Inhalt.
Wenn Sie kompliziertere Daten haben oder spezifischere UI-Komponenten benötigen, können Sie Funktionen wie Bausteine wieder verwenden:
Ich hoffe, das hilft. Wenn Sie nach besseren Beispielen suchen, können Sie den Quellcode hinter Shinys Eingabe- und Ausgabeelementen (z. B.
selectInput()
) überprüfen , bei denen es sich im Wesentlichen um Funktionen handelt, die HTML-Tags ausspucken. Ein Template-Motor könnte auch funktionieren, aber es besteht keine wirkliche Notwendigkeit, wenn Sie bereitshtmltools
+ die volle Leistung von R haben.quelle
Vielleicht könnten Sie überlegen, in
glue()
und zu schauenget()
.erhalten():
get()
kann Strings in Variablen / Objekte verwandeln.So könnte man verkürzen:
zu
(siehe das folgende Beispiel).
kleben():
glue()
bietet eine Alternative zupaste0()
. Es könnte besser lesbar sein, wenn Sie viele Zeichenfolgen und Variablen zu einer Zeichenfolge zusammenfassen. Ich gehe davon aus, dass es auch der Syntax Ihres gewünschten Ergebnisses nahe kommt.Anstatt:
Sie würden schreiben:
Ihr Beispiel würde vereinfachen:
Verwenden von:
Alternativen:
Ich denke, htmltemplate ist eine gute Idee, aber ein weiteres Problem sind die unerwünschten Leerzeichen: https://github.com/rstudio/htmltools/issues/19#issuecomment-252957684 .
quelle