Using actionButton with marker-click and button-click on observeEvent returning no features

819 views Asked by At

thanks in advance for reading my post.

Firstly, let me say that I am sure the solution is probably simple, and don't let my wall of text dissuade you. I am new to shiny.

The context: I'm using the latest version of R (4.0.3). I have a shiny leaflet app populated with addMarkers(). When you click a marker, a, popup with information appears (Name, type, address, email, region, survey). This is the standard addMarkers(data=...,popup=...) call.

In addition, the pop-up contains an actionButton ("see more details" button) that listens to an observeEvent (i.e. When the user clicks the button). The observeEvent should bring up the same popup details and more in a shinyalert.

The problem: The action button on the popup returns nothing, instead of the feature that was clicked on.

The hypothesized solution: i suspect it has something to do with the button click needing a unique ID, and subsequently a unique ID in the observeEvent. I have no idea how to do that within the JavaScript of the actionButton line. I have tried with reactiveValues to no avail.

Another layer of complexity: the solution must not use leafletProxy. The reason is that markerClusteroptions(JS=....) piped into leafletProxy break. I have custom cluster colours. They will break if I add leafletproxy. This is a known issue in shiny.

Javascript links: I need this to work in R, not JS. However, if a solution has a JS wrapper for R, I'm open to that.

Please help!

Example fully functional code:

library(leaflet)
library(shiny)
library(shinyalert)

myData <- data.frame(
  lat = c(54.406486, 53.406486),
  lng = c(-2.925284, -1.925284),
  id = c(1,2),
  name= c("Location1", "Location2")
)
    
ui <- fluidPage(
  leafletOutput("map"),
  p(),
  useShinyalert()
)

server <- shinyServer(function(input, output) {
  data <- reactiveValues(clickedMarker=NULL)
  # produce the basic leaflet map with single marker
  output$map <- renderLeaflet(
    leaflet() %>%
      addProviderTiles("CartoDB.Positron") %>%
      #dont worry about the spacing its just an example
      addMarkers(lat = myData$lat, lng = myData$lng, layerId = myData$id, popup= (paste0(myData$name, myData$lat, myData$lng,actionButton("showmodal", "Expand to show more details", onclick = 'Shiny.onInputChange(\"button_click\",  Math.random())'))
      ))#close circle markers  
  )#close render
  # observe the marker click info and print to console when it is changed.

  observeEvent( input$showmodal,{
    {
    print("observed map_marker_click and button click")
    data$clickedMarker <- input$showmodal
    print(data$clickedMarker)
    shinyalert(title= "testing",
    text= data$lng,
          data$name)

  })#close observeevent
})#close shiny

shinyApp(ui, server)

Addendum: This post is not a duplicate, as I have tried to solve this with the given links to no avail.

This link: the answer given does not deploy in my R version. It also sounds like the answer did not completely solve the user's problem regardless of the error as it returned blank s. The answer also seemed more complicated than the solution for my problem likely is.

This link: The user had a similar problem to me, and a comment suggested an answer but I do not understand how to implement it. No direct solution was given. The comment was, "You could use input$mymap_marker_click and save it in a reactiveValue to remember which marker was clicked last. In the given sample data, the markers does not seem to have ids though".

This link: This link example works, but I don't understand how I could reconfigure the answer for my app and my code. It's just different enough that I don't have the knowledge to figure it out.

This link: does kind of what I want but I have an additional button click before so I'm not sure how to implement that. Didn't work for my app when I tried to follow a similar approach storing reactive values and observeEvent.

This link: Very close to what I want, but instead of observing $map_marker_click, Im observing $button_click. I try to implement it and it returns an error. The second solution by nilsole I cannot use because leafletproxy conflicts with JS in my code.

Edit: Thank you so much geovany! solved it :)

1

There are 1 answers

0
Geovany On BEST ANSWER

You should observe button_click instead of showmodal, actually showmodal is ignored because it is inside the popup. You can not retrieve the "name", "lng", and "lat" from data without having there. Initially data only contains clickedMarker with NULL, later when the user click on the button it will have again just NULL. You can get the value of the layerID parameter using input$map_marker_click$id and then use the id value as an index to access values inside myData. Below is a modification of you code that implements the idea.

library(leaflet)
library(shiny)
library(shinyalert)

myData <- data.frame(
  lat = c(54.406486, 53.406486),
  lng = c(-2.925284, -1.925284),
  id = c(1,2),
  name= c("Location1", "Location2")
)

ui <- fluidPage(
  leafletOutput("map"),
  p(),
  useShinyalert()
)

server <- shinyServer(function(input, output) {
  # produce the basic leaflet map with single marker
  output$map <- renderLeaflet(
    leaflet() %>%
      addProviderTiles("CartoDB.Positron") %>%
      #dont worry about the spacing its just an example
      addMarkers(
        lat = myData$lat, lng = myData$lng, layerId = myData$id, 
        popup= (paste0(
          myData$name, ": ", myData$lat, ", ", myData$lng,
          actionButton("showmodal", "Expand to show more details", 
                       onclick = 'Shiny.onInputChange("button_click",  Math.random())')
        ))
      )#close circle markers  
  )#close render
  # observe the marker click info and print to console when it is changed.
  
  observeEvent( input$button_click,{
    print("observed button_click and get id from map_marker_click$id")
    id <- input$map_marker_click$id
    shinyalert(
      title = "testing",
      text = paste0(myData$name[id], ": ", myData$lat[id], ", ", myData$lng[id])
    )
  })
  
})#close shiny

shinyApp(ui, server)