DT icon indicating copy to clipboard operation
DT copied to clipboard

Natural sorting with the 'natural' plugin and type = natural-nohtml breaks links

Open jzadra opened this issue 2 years ago • 3 comments

I have a couple columns that have numbers displayed but are html links. DT on its own does not sort hyperlink numbers stored as correctly, so I'm using the 'natural' plugin.

Why I set columnDefs to type = 'natural' the sorting is still incorrect as it sorts on the html instead of the text, but the links still work. When I instead use type = 'natural-nohtml' it sorts correctly, but the links are broken.

jzadra avatar Apr 06 '22 15:04 jzadra

I don't know this plugin but you can achieve that with the render option. I can show you if you give more details.

stla avatar Apr 09 '22 17:04 stla

Thanks for the offer! So I have a data table where 2 of the columns are hyperlinks that open a modal dialogue. Oddly using the "natural" plugin and type "natural-nohtml" for those columns (targets = 3:4) will work correctly the first 2-3 times, but then it starts opening a blank modal dialogue beyond that.

Server:

email_table <- cc_emails$email_table %>% 
    rename(Unsubs = Unsubscribed,
           Date = `Last Sent`)
 
  dt_email_table <- email_table %>%
    mutate(Opened = glue("<a id='email_opened_input_{campaign_id}' href='#' class='action-button' onclick='Shiny.setInputValue(id = &#39;email_opened_click&#39;, value = &#39;{campaign_id}&#39;);'>{Opened}</a>")) %>%
    mutate(Clicks = glue("<a id='email_clicks_input_{campaign_id}' href='#' class='action-button' onclick='Shiny.setInputValue(id = &#39;email_clicks_click&#39;, value = &#39;{campaign_id}&#39;);'>{Clicks}</a>")) %>%
    mutate(across(where(is.numeric), as.integer)) %>% 
    mutate(Date = as_date(Date)) %>% 
    #mutate(Date = as_date(Date) %>% nice_date()) %>% 
    deselect(campaign_id) %>% 
    relocate(Bounced, .before = `Bounce Rate`) %>% 
    relocate(Unsubs, .after = `Bounce Rate`)
  
  output$emails <- renderDT(server = F, {
    datatable(dt_email_table,
              escape = FALSE,
              options = list(pageLength = 5,
                             columnDefs = list(list(width = "80%", targets = 0), 
                                               list(width = "20%", targets = 1), 
                                               list(className = "dt-center", targets = 1:9),
                                               list(type = "natural-nohtml", targets = 3:4),
                                               list(orderSequence = c('desc', 'asc'), targets = 1:5)),
                             autoWidth = T,
                             scrollX = T,
                             order = list(1, "desc")),
              rownames = F,
              filter = "none",
              selection = "none",
              plugins = "natural")
  })

#Modal Dialogues

#Opens
  observeEvent(input$email_opened_click, {
    showModal(modalDialog(
      title = "Opens",
      tableOutput("opened_table"),
      size = "m",
      easyClose = T
    ))
  })
  
  output$opened_table <- renderTable({
    req(input$email_opened_click)
    cc_emails$opens %>% 
      filter(campaign_id == input$email_opened_click) %>% 
      deselect(campaign_id) %>% 
      arrange(name) %>% 
      rename(Name = name, `E-mail` = email_address)
  })
  
  # Clicks
  observeEvent(input$email_clicks_click, {
    showModal(modalDialog(
      title = "Clicks",
      tableOutput("clicks_table"),
      size = "m",
      easyClose = T
    ))
  })
  
  output$clicks_table <- renderTable({
    req(input$email_clicks_click)
    cc_emails$clicks %>% 
      filter(campaign_id == input$email_clicks_click) %>% 
      deselect(campaign_id) %>% 
      arrange(name) %>% 
      rename(Name = name, `E-mail` = email_address)
  })
  

UI:

fluidRow(
    column(width = 12, align = "center",
           wellPanel(style = "background: #113e66; color: white",
             h3("Email Campaigns"),
             h6(glue("Total contacts in database: {scales::comma(cc_emails$total_contacts)}")),
             DT::DTOutput("emails"))
    )
  )

jzadra avatar Apr 12 '22 17:04 jzadra

Damn, your code is huge...

Here is an example:

library(DT)

render <- c(
  "function(data, type, row){",
  "  if(type === 'sort'){",
  "    var parser = new DOMParser();",
  "    var doc = parser.parseFromString(data, 'text/html');",
  "    data = doc.querySelector('a').innerText;",
  "  }",
  "  return data;",
  "}"
)

dat <- data.frame(
  a = c("AAA", "BBB", "CCC"), 
  b = c(
    '<a href="#" id = "Z" onclick = "Ztest">aaaaa</a>', 
    '<a href="#" id = "A" onclick = "Atest">bbbbb</a>',
    '<a href="#" id = "J" onclick = "Jtest">jjjjj</a>'
  )
)

datatable(
  dat, 
  escape = FALSE,
  options = list(
    columnDefs = list(
      list(targets = 2, render = JS(render))
    )
  )
)

However, I don't understand: even without my render option, thee sorting is "correct". I expected to see "bbbbb" at first position but no, it is at second position.

stla avatar Apr 13 '22 10:04 stla