Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Click events for leafpm editToolbar buttons #112

Open
chintanp opened this issue May 12, 2020 · 5 comments
Open

Click events for leafpm editToolbar buttons #112

chintanp opened this issue May 12, 2020 · 5 comments

Comments

@chintanp
Copy link

I am using mapedit in Shiny using the callModule as here

selections <- callModule(selectMod, "test-mod", m)

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?

@timelyportfolio
Copy link
Contributor

timelyportfolio commented May 13, 2020

@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.

@timelyportfolio
Copy link
Contributor

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

@chintanp
Copy link
Author

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.

@timelyportfolio
Copy link
Contributor

@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.

@chintanp
Copy link
Author

@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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants