R: UI / html- टैग से कोड तर्क को अलग ढंग से कैसे करें?


9

मुसीबत

जब गतिशील रूप से ui- एलिमेंट्स ( shiny.tag,, shiny.tag.list...) बनाते हैं , तो मुझे अक्सर अपने कोड लॉजिक से इसे अलग करना मुश्किल लगता है और आमतौर पर नेस्टेड की एक गड़बड़ गंदगी tags$div(...), छोरों और सशर्त बयानों के साथ मिश्रित होता है। कष्टप्रद और बदसूरत दिखने के लिए, HTML- टेम्प्लेट में परिवर्तन करते समय, यह भी त्रुटि-प्रवण है, उदाहरण के लिए।

उदाहरण के लिए

मान लें कि मेरे पास निम्नलिखित डेटा-संरचना है:

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")
    )
  )  
)

अगर मैं अब इस संरचना को यूआई-टैग में धकेलना चाहता हूं, तो मैं आमतौर पर कुछ इस तरह से समाप्त करता हूं:

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)

जैसा कि आप देख सकते हैं, यह पहले से ही काफी गड़बड़ है और अभी भी मेरे वास्तविक उदाहरणों की तुलना में कुछ भी नहीं है।

वांछित समाधान

मैं आर के लिए एक अस्थायी इंजन के करीब कुछ खोजने की उम्मीद कर रहा था , जो टेम्पलेट्स और डेटा को अलग से परिभाषित करने की अनुमति देगा :

# 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}}"
  )
)

पिछले प्रयास

सबसे पहले, मैंने सोचा था कि shiny::htmlTemplate()एक समाधान की पेशकश कर सकता है, लेकिन यह केवल फाइलों और पाठ स्ट्रिंग के साथ काम करेगा, shiny.tagएस नहीं । मैंने कुछ आर-पैकेज जैसे व्हिस्कर पर भी नज़र डाली थी , लेकिन लगता है कि वे समान सीमा वाले हैं और टैग या सूची-संरचनाओं का समर्थन नहीं करते हैं।

धन्यवाद!


आप wwwफ़ोल्डर के तहत एक सीएसएस फ़ाइल को बचा सकते हैं और फिर स्टाइल शीट लगा सकते हैं?
एमकेए

सीएसएस लागू करने के मामले में, निश्चित रूप से, लेकिन मैं एक सामान्य दृष्टिकोण की तलाश में था जो एचटीएमएल-संरचना में बदलाव की अनुमति देता है, आदि
आराम ईगल

काम करने के लिए उपयोगी लेकिन जोड़ने और टिप्पणी करने के लिए कुछ भी नहीं है। आदर्श रूप में, htmlTemplate()सशर्त, के लिए अनुमति देते हैं और आला हैंडल लूप होता है, मूँछ, टहनी ...
विल

जवाबों:


2

मुझे चमकदार एचटीएमएल टैग (या htmltoolsटैग) बनाने वाले फ़ंक्शंस का उपयोग करके रचना योग्य और पुन: प्रयोज्य यूआई तत्व बनाना पसंद है । आपके उदाहरण ऐप से, मैं एक "पृष्ठ" तत्व की पहचान कर सकता हूं, और फिर दो सामान्य सामग्री कंटेनर, और फिर उन लोगों के लिए कुछ कार्य बना सकता हूं:

library(shiny)

my_page <- function(...) {
  div(style = "height: 400px; background-color: lightblue;", ...)
}

my_content <- function(..., height = NULL, color = NULL) {
  style <- paste(c(
    sprintf("height: %spx", height),
    sprintf("background-color: %s", color)
  ), collapse = "; ")

  div(style = style, ...)
}

और फिर मैं अपने यूआई को इस तरह से बना सकता हूं:

my_ui <- my_page(
  my_content(
    p("impeach"),
    h1("orange"),
    color = "orange",
    height = 100
  ),
  my_content(
    p("tool"),
    color = "yellow",
    height = 50
  )
)

server <- function(input, output) {}
shinyApp(my_ui, server)

किसी भी समय मुझे किसी तत्व के स्टाइल या HTML को ट्विक करने की आवश्यकता है, मैं सीधे उस फ़ंक्शन पर जाता हूं जो उस तत्व को उत्पन्न करता है।

इसके अलावा, मैंने अभी इस मामले में डेटा को इनलाइन किया है। मुझे लगता है कि आपके उदाहरण में डेटा संरचना वास्तव में यूआई चिंताओं (स्टाइलिंग, एचटीएमएल टैग) के साथ डेटा को मिलाती है, जो कुछ जटिल-नेस की व्याख्या कर सकती है। एकमात्र डेटा जो मैं देख रहा हूं, वह हैडर के रूप में "ऑरेंज", और कंटेंट के रूप में "महाभियोग" / "टूल"।

यदि आपके पास अधिक जटिल डेटा है या अधिक विशिष्ट UI घटकों की आवश्यकता है, तो आप बिल्डिंग ब्लॉक्स की तरह फिर से कार्यों का उपयोग कर सकते हैं:

my_content_card <- function(title = "", content = "") {
  my_content(
    h1(title),
    p(content),
    color = "orange",
    height = 100
  )
}

my_ui <- my_page(
  my_content_card(title = "impeach", content = "orange"),
  my_content(
    p("tool"),
    color = "yellow",
    height = 50
  )
)

उम्मीद है की वो मदद करदे। यदि आप बेहतर उदाहरणों की तलाश कर रहे हैं, तो आप शाइन के इनपुट और आउटपुट तत्वों (जैसे selectInput()) के पीछे स्रोत कोड की जांच कर सकते हैं, जो अनिवार्य रूप से HTML टैग को थूकने वाले कार्य हैं। एक अस्थायी इंजन भी काम कर सकता है, लेकिन जब आपको पहले से ही htmltoolsआर की पूरी शक्ति मिल गई है तो कोई वास्तविक आवश्यकता नहीं है।


जवाब के लिए धन्यवाद! मैं इसे इस तरह से भी करता था, लेकिन यह काफी अव्यवहारिक हो जाता है जब html का बहुत अधिक उपयोग नहीं किया जा सकता है। मुझे लगता है कि किसी तरह का टेम्पलेट-इंजन एकमात्र व्यवहार्य समाधान होगा: /
कम्फर्ट ईगल

1

हो सकता है आप में देख पर विचार कर सकते glue()हैं और get()

प्राप्त():

get() स्ट्रिंग को चर / वस्तुओं में बदल सकते हैं।

तो आप छोटा कर सकते हैं:

if (y[["type"]] == "h1") {
    tags$h1(y[["value"]])
} else if (y[["type"]] == "p") {
    tags$p(y[["value"]])
}

सेवा

get(y$type)(y$value)

(नीचे उदाहरण देखें)।

गोंद ():

glue()के लिए एक विकल्प प्रदान करता है paste0()। यह अधिक पठनीय हो सकता है यदि आप स्ट्रिंग के लिए बहुत सारे स्ट्रिंग्स और चर को केंद्रित करते हैं। मुझे लगता है कि यह आपके वांछित परिणाम के सिंटैक्स के करीब भी दिखता है।

के बजाय:

paste0("height: ", x$height, "px; background-color: ", x$color, ";")

आप लिखेंगे:

glue("height:{x$height}px; background-color:{x$color};")

आपका उदाहरण सरल होगा:

tagList(
  tags$div(style = "height: 400px; background-color: lightblue;",
    lapply(my_data, function(x){
      tags$div(style = glue("height:{x$height}px; background-color:{x$color};"),
        lapply(x$content, function(y){get(y$type)(y$value)}) 
      )
    })
  )
)

का उपयोग करते हुए:

library(glue)
my_data <- list(
  container_a = list(
    color = "orange",
    height = 100,
    content = list(
      vec_a = list(type = "p", value = "impeach"),
      vec_b = list(type = "h1", value = "orange")
    )
  ),
  container_b = list(
    color = "yellow",
    height = 50,
    content = list(
      vec_a = list(type = "p", value = "tool")
    )
  )  
)

विकल्प:

मुझे लगता है कि htmltemplate एक अच्छा विचार है, लेकिन एक और समस्या अवांछित व्हाट्सएप: https://github.com/rstudio/htmltools/issues/19#issuecomment-252957684 है


आपके सहयोग के लिए धन्यवाद। जबकि आपका कोड अधिक कॉम्पैक्ट है, html और तर्क के मिश्रण का मुद्दा बना हुआ है। : /
आराम ईगल
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.