Click events for leafpm editToolbar buttons
chintanp opened this issue · comments
I am using mapedit
in Shiny using the callModule
as here
mapedit/inst/examples/shiny_modules.R
Line 16 in b5bad16
I want to run some code when a polygon is finished drawing and another code when polygon is deleted. I am using an observeEvent
on reactives selections()$finished
and selections()$deleted
to achieve this. While this works for the first run to catch both events, the selections()$deleted
is not NULL subsequently and therefore the corresponding observeEvent is fired even when just a shape is drawn.
Are there specific events tied to the draw/delete buttons in the leafpm
edit toolbar? If so, an example usage would be helpful.
If not supported currently, any suggestions on how this can be achieved using for example, shinyjs
?
@chintanp I see what you are saying. Isolating events is I think impossible using the reactiveValue inside the reactive
since the parent reactive
change will trigger the observer for drawn, deleted, etc. I had not considered this previously and will spend some time thinking through a better solution. For now you could observe the raw events and respond that way. Here is an example.
library(mapedit)
library(mapview)
library(leaflet)
library(shiny)
m <- mapview(breweries)@map
ui <- tagList(
editModUI("test-edit", height=600)
)
server <- function(input, output, session) {
crud <- callModule(
editMod,
"test-edit",
leafmap = m,
targetLayerId = "breweries"
)
observeEvent(crud()$deleted, {
print('delete')
str(crud()$deleted)
})
observeEvent(crud()$drawn, {
print('drawn')
str(crud()$drawn)
})
observeEvent(input[["test-edit-map_draw_deleted_features"]], {
print('raw delete event will only update on delete')
})
}
shinyApp(ui, server)
Note: I tried every iteration that I could to properly isolate and none seemed to work.
Code Examination
In lines we set up a reactiveValues
container which would allow the isolation/separation desired. However, in the return in lines we use a reactive
which will trigger observers for any non-null list item whether they are changed (dirty) or not.
@chintanp another option would be to track changes manually with identical
. This is a lot to ask a user, and I'd like to find a better way, but for now:
library(mapedit)
library(mapview)
library(leaflet)
library(shiny)
m <- mapview(breweries)@map
ui <- tagList(
editModUI("test-edit", height=600)
)
server <- function(input, output, session) {
crud <- callModule(
editMod,
"test-edit",
leafmap = m,
targetLayerId = "breweries"
)
deleted <- isolate(crud()$deleted)
drawn <- isolate(crud()$drawn)
observeEvent(crud()$deleted, {
if(!identical(crud()$deleted, deleted)) {
print('deleted')
str(crud()$deleted)
deleted <<- crud()$deleted
}
})
observeEvent(crud()$drawn, {
if(!identical(crud()$drawn, drawn)) {
print('drawn')
str(crud()$drawn)
drawn <<- crud()$drawn
}
})
observeEvent(input[["test-edit-map_draw_deleted_features"]], {
print('raw delete event will only update on delete')
})
}
shinyApp(ui, server)
I ended up implementing something similar, using memoryCache
. I create a unique key per session and update it with the edit_id
of the sf df row, like so:
set(paste0("deleted", session$token), selections()$deleted$edit_id)
when the first time delete happens, and check in an if
condition whether the edit_id
is same.
For subsequent deletes, I use
set(paste0("deleted", session$token), dplyr::last(selections()$deleted$edit_id))
to do a similar check.
It is hacky and I do not feel good about it, as edit_id
is undocumented. Further, I had to change this to use selections()$deleted$X_leaflet_id
when using leaflet.extras
drawToolbar.
The isolate - identical
workflow is cleaner. Will post further if I have any issues.
@chintanp thanks for the report. I'd like to allow the isolation, but I think the change would require a breaking API change, so I'll leave this open to see if anyone expresses interest or proposes other solutions.
@timelyportfolio another (maybe associated) useful feature would be the ability to programmatically toggle the toolbar button states. For example, the issue #113 can be avoided if I can say only allow the "delete" button to be clickable when there are "drawn/editable" features on the map, and then become dormant as soon as all the "drawn/editable" features have been deleted.