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

Popup customization #8

Closed
Teolone88 opened this issue Jul 4, 2021 · 22 comments
Closed

Popup customization #8

Teolone88 opened this issue Jul 4, 2021 · 22 comments

Comments

@Teolone88
Copy link

Hi,

Is there any way to customize the calendar() popup with different user inputs when isReadOnly = FALSE?

Should I change the inputs from https://github.com/dreamRs/toastui/blob/master/inst/htmlwidgets/calendar.js under
cal.createSchedules([{}]) & Shiny.setInputValue({})

Please forgive my n000biness in Js.

Best,
Teo

@pvictor
Copy link
Member

pvictor commented Jul 5, 2021

Hello,

It might be difficult to add Shiny input widget or sophisticated elements in the built-in pop-up, a solution can be to use Shiny's logic with insertUI() / removeUI() and an absolutePanel(), like that you can put whatever you want in the pop-up. Here's a full example:

# Calendar: custom popup --------------------------------------------------


library(shiny)
library(toastui)

## Schedules data
schedules <- cal_demo_data()
# add an id
schedules$id <- seq_len(nrow(schedules))
# add custom data in "raw" attribute
schedules$raw <- lapply(
  X = seq_len(nrow(schedules)),
  FUN = function(i) {
    list(
      status = sample(c("Completed", "In progress", "Closed"), 1)
    )
  }
)



## App

ui <- fluidPage(
  fluidRow(
    column(
      width = 8, offset = 2,
      tags$h2("Custom popup made with Shiny"),
      calendarOutput(outputId = "cal"),
      uiOutput("ui")
    )
  )
)

server <- function(input, output, session) {
  
  output$cal <- renderCalendar({
    calendar(view = "month", taskView = TRUE, useDetailPopup = FALSE) %>% 
      cal_props(cal_demo_props()) %>% 
      cal_schedules(schedules) %>%
      cal_events(
        clickSchedule = JS(
          "function(event) {", 
          "Shiny.setInputValue('calendar_id_click', {id: event.schedule.id, x: event.event.clientX, y: event.event.clientY});", 
          "}"
        )
      )
  })
  
  
  observeEvent(input$calendar_id_click, {
    removeUI(selector = "#custom_popup")
    id <- as.numeric(input$calendar_id_click$id)
    # Get the appropriate line clicked
    sched <- schedules[schedules$id == id, ]
    
    insertUI(
      selector = "body",
      ui = absolutePanel(
        id = "custom_popup",
        top = input$calendar_id_click$y,
        left = input$calendar_id_click$x, 
        draggable = FALSE,
        width = "300px",
        tags$div(
          style = "width: 250px; position: relative; background: #FFF; padding: 10px; box-shadow: 0px 0.2em 0.4em rgb(0, 0, 0, 0.8); border-radius: 5px;",
          actionLink(
            inputId = "close_calendar_panel", 
            label = NULL, icon = icon("close"), 
            style = "position: absolute; top: 5px; right: 5px;"
          ),
          tags$br(),
          tags$div(
            style = "text-align: center;",
            tags$p(
              "Here you can put custom", tags$b("HTML"), "elements."
            ),
            tags$p(
              "You clicked on schedule", sched$id, 
              "starting from", sched$start,
              "ending", sched$end
            ),
            tags$b("Current status:"), tags$span(class = "label label-primary", sched$raw[[1]]$status),
            radioButtons(
              inputId = "status",
              label = "New status:",
              choices = c("Completed", "In progress", "Closed"),
              selected = sched$raw[[1]]$status
            )
          )
        )
      )
    )
  })
  
  observeEvent(input$close_calendar_panel, {
    removeUI(selector = "#custom_popup")
  })
  
  rv <- reactiveValues(id = NULL, status = NULL)
  observeEvent(input$status, {
    rv$id <- input$calendar_id_click$id
    rv$status <- input$status
  })
  
  output$ui <- renderUI({
    tags$div(
      "Schedule", tags$b(rv$id), "has been updated with status", tags$b(rv$status)
    )
  })
  
}

shinyApp(ui, server)

let me know if you have any questions about the above code

Victor

@Teolone88
Copy link
Author

Really smooth!!! Thank you so much Victor. I was not aware of the absolutePanel function.
You should commit this option as it makes sense to customize your pop up going forward.

@januz
Copy link

januz commented Oct 8, 2021

Just came from the documentation to your Github repo to see whether one can select a date on the monthly calendar and get a menu to enter data for that specific date (or a date range starting from that date). From what I read here, this seems possible, correct? It would be amazing if you would include this as a feature!

@pvictor
Copy link
Member

pvictor commented Oct 14, 2021

@januz yes you can interactively add schedules in a calendar, but it will only work in Shiny since you need a backend to save data.

@gavril0
Copy link

gavril0 commented Nov 22, 2021

This work well when the schedule is already created. However, the event is not triggered when creating a new schedule by clicking on some other part of the calendar.

image

For example, "clickSchedule" is triggered when clicking on the schedules with blue background but not when defining a new period (see period defined on Wednesday in the above image).

I looked at "beforeCreateEvent" which seems to be the relevant event but I am not sure how to redefine it (I am JS/htmlwidget newbie).

Accessorily, let me state some reasons why I want to do that in case I should use a different approach:

  1. I want to be able to control id of the newly created schedule (I already have unique ids defined in other part of my application).
  2. I already have title, body and calendardId info in my app when creating a new schedule. I am using the calendar to define the start and end times when creating a schedule, and to visualize/modify time period of existing schedules. I could use a date/time picker but I like better the calendar visualization which shows empty time slots.

UPDATE Looking at your example I see that there are shiny events that I could use:

observeEvent(input$cal_add, {
  new <- input$cal_add
  new$id <-patient_id  # new id
  new$title <- "X,Y"
  new$body <- paste0("patient id:", patient_id)
  new$calendardId <- 2
  cal_proxy_add("cal", new)
})

observeEvent(input$cal_update, {
  cal_proxy_update("cal", input$cal_update)
})
  
observeEvent(input$cal_delete, {
  cal_proxy_delete("cal", input$cal_delete)
})

I am still exploring it (are these events documented? why use cal_proxy_xxxx?)

@pvictor
Copy link
Member

pvictor commented Nov 24, 2021

Hello @gavril0 ,
Can you open a new issue with a reproducible example ?
It's possible that the documentation is incomplete, it's a work in progress

@nick-youngblut
Copy link

I looked at "beforeCreateEvent" which seems to be the relevant event but I am not sure how to redefine it (I am JS/htmlwidget newbie).

@gavril0 did you figure this out? I would also like to create a custom pop-up for new events, but I don't see any examples of how to do this (calendar-popup-shiny.R just works for existing events... after applying the bugfix for v0.3).

@nick-youngblut
Copy link

UPDATE Looking at your example I see that there are shiny events that I could use:

@gavril0 at least for me, input$cal_update is not created, which seems to be due to using a custom-popup. Did you find a way around this, such as "manually" creating the value in cal_proxy_update(proxy, value)?

@gavril0
Copy link

gavril0 commented Jan 30, 2024

@nick-youngblut I ended up not using pop-up. However, I have to go back to the issue because I need to update my
code to the new version of calendar

@nick-youngblut
Copy link

Thanks @gavril0 for letting me know!

@pvictor any suggestions on how to create a custom pop-up for new events, and also for updating the toastui calendar with a custom pop-up (see above)?

@pvictor
Copy link
Member

pvictor commented Jan 31, 2024

Hello @nick-youngblut, can you provide an exemple to reproduce the issue ?

@nick-youngblut
Copy link

@pvictor I have 2 issues:

  1. It's not clear to me how to create a custom pop-up for creating new events. I have created a custom pop-up for viewing/editing existing events (see attached), but how do I create a pop-up for new events?
  2. It's not clear how to update a rendered calendar once the user has edited an event via a custom pop-up. For my custom pop-up, it appears that the input$cal_update object is not created, so I cannot simply use cal_proxy_update(proxy, input$cal_update) as in this example.

I need a custom pop-up for both creating new events and updating existing events, because I need to include 2 drop-downs in the pop-up that the user MUST select when creating an event. This is why I cannot simply use Google Calendar, since one cannot add mandatory drop-downs for creating events.

If you could point me to any documentation/examples, or provide some here, I'd appreciate it.

I'm using toastui v0.3.

Screenshot 2024-01-31 at 7 57 48 AM

@pvictor
Copy link
Member

pvictor commented Jan 31, 2024

For the first issue, you can try this example : https://github.com/dreamRs/toastui/blob/master/inst/examples/calendar-custom-create.R, note that you need last GitHub version where I added support for selectdatetime event.

For the second one,, you should be able to do something like this with your own infos about the schedule to update :

library(shiny)
library(toastui)
library(lubridate)

ui <- fluidPage(
  tags$h2("Update schedule"),
  actionButton("update", "Update"),
  calendarOutput(outputId = "cal")
)

server <- function(input, output, session) {
  
  output$cal <- renderCalendar({
    calendar() %>% 
      cal_schedules(
        id = "MY_CUSTOM_SCHEDULE_ID",
        calendarId = "MY_CUSTOM_CALENDAR_ID",
        title = "Title",
        body = "Some description",
        start = Sys.Date(),
        end = Sys.Date(),
        category = "allday"
      )
  })
  
  observeEvent(input$update, {
    date <- Sys.Date() + sample(-10:10, 1)
    cal_proxy_update(
      "cal",
      list(
        id = "MY_CUSTOM_SCHEDULE_ID", 
        calendarId = "MY_CUSTOM_CALENDAR_ID",
        title = sample(ls(pos = "package:base"), 1),
        start = date,
        end = date
      )
    )
  })
  
}

shinyApp(ui, server)

@nick-youngblut
Copy link

nick-youngblut commented Jan 31, 2024

Thanks @pvictor for the detailed response!

I haven't tried the 1st issue solution yet, but the for 2nd, cal_proxy_update() does nothing. I know that it is triggered, but the calendar event is not updated.

What is actually needed for the value parameter in cal_proxy_update()? When I run the ex-proxy-schedule.R example, and print input$my_calendar_update after editing an event, I get:

$schedule
$schedule$id
[1] "shd_ec425d5b"

$schedule$title
[1] "test"

$schedule$location
[1] "test"

$schedule$start
[1] "2024-01-30T00:00:00-08:00"

$schedule$end
[1] "2024-01-30T00:00:00-08:00"

$schedule$isAllday
[1] FALSE

$schedule$category
[1] "time"

$schedule$calendarId
[1] "clnd_00c2cdbf"


$changes
$changes$title
[1] "test1"

Based on the cal_proxy_update code, it appears that I need to provide:

  • value$changes & value$schedule
  • value$schedule$calendarId
  • value$schedule$id
  • A list of values to change for value$changes

I've tried this:

$schedule$id
[1] "dxsr26fhl7xkk8m2cqfo121958"

$schedule$calendarId
[1] "[email protected]"


$changes
$changes$title
[1] "Nick Youngblut"

$changes$start
[1] "2024-01-30 09:55:00 PST"

$changes$end
[1] "2024-01-30 10:50:00 PST"

However, this input to cal_proxy_update doesn't seem to do anything. Where does the $schedule$id value come from?

UPDATE:

I see that I have to use input$calendar_id_click$id as the ID. The start and end times now update. However, to render the custom pop-up for editing events, I'm using the data.frame of events used for rendering the calendar. This data.frame is not updated by cal_proxy_update, so the pop-up info is not updated.
I need to get the updated event info after cal_proxy_update is run, but I don't see how to pull the event info. The cal_* functions seems to focus on adding data/params to the calendar and not retrieving (updated) info from the calendar.
I was hoping that input$my_calendar_schedules (in my case input$cal_sechedules) would provide the updated schedule information for all events (schedules), but it seems to only provide a list for the most recent event (schedule) that is on the calendar (e.g., the event for today and not the other events from previous days).

@pvictor
Copy link
Member

pvictor commented Feb 1, 2024

cal_proxy_update() does nothing

the example I provided doesn't work for you?

cal_proxy_update() update an existing schedule using its id and calendarId to identify it, if you do not provide id / calendarId when creating a schedule, they will be generated automatically.

input$<outputId>_update is an event sent when using builtin popup, if you do not use buitlin popup this event isn't triggered.

I need to get the updated event info after cal_proxy_update

You already have that since you called cal_proxy_update() with it, calendar here is just for display
You have to update yourself your starting data.frame with the infos you collect from your custom popup, the calendar cannot do your backend.

@nick-youngblut
Copy link

nick-youngblut commented Feb 1, 2024

the example I provided doesn't work for you?

A challenge for me in creating a custom pop-up allowing for schedule editing was that I not only had to figure out what data structure to provide as the value parameter to cal_proxy_update(), but I also had to edit the reactive data.frame object that I was using to fill the values in the custom pop-up. Once I figured out the list structure for the value parameter of cal_proxy_update() (thanks for your help!), the schedule in the calendar would update (e.g., the schedule start time), but when I clicked on the pop-up again, the values in the pop-up (e.g., time or title) were not changing. I had to also update the reactive data.frame object in addition to running cal_proxy_update() so that when the custom pop-up was rendered, it used the updated values instead of the original schedule values.

The pop-up for schedule editing seems to be correctly working fully. Thanks for all of your help.

I was also able to create a custom pop-up for creating new events (after updating the package to the latest version on github). Will you be releasing a new version on CRAN soon, or are you waiting on some more updates first?

Thanks! 🙏

@nick-youngblut
Copy link

@pvictor in the calendar-custom-create.R example, you use showModal(modalDialog()) to show a model instead of a pop-up at the location on the calendar where the user clicked. One can use input$calendar_id_click$y and input$calendar_id_click$x for a custom pop-up that edits an existing schedule, but input$calendar_id_click$y and input$calendar_id_click$x do not seem to be available for a custom pop-up for creating a new event, as described in calendar-custom-create.R.

Is there a way to create a custom pop-up for creating an event at the location on the calendar (e.g., day) were the user clicks?

@pvictor
Copy link
Member

pvictor commented Feb 2, 2024

Is there a way to create a custom pop-up for creating an event at the location on the calendar (e.g., day) were the user clicks?

It's certainly possible, but I find it hard to see the added value compared to the complexity it would require to implement. The modal solution seems simple, robust and immediately available.

@nick-youngblut
Copy link

The modal solution seems simple, robust and immediately available.

After trying out the modal solution, I agree... especially given that one can obtain the date/time info from where the user clicks on the calendar to fill in date/time info in the modal.

@toxintoxin
Copy link

@pvictor in the calendar-custom-create.R example, you use showModal(modalDialog()) to show a model instead of a pop-up at the location on the calendar where the user clicked. One can use input$calendar_id_click$y and input$calendar_id_click$x for a custom pop-up that edits an existing schedule, but input$calendar_id_click$y and input$calendar_id_click$x do not seem to be available for a custom pop-up for creating a new event, as described in calendar-custom-create.R.

Is there a way to create a custom pop-up for creating an event at the location on the calendar (e.g., day) were the user clicks?

How can I add namespaces to javascript in calendar-custom-create.R, if you know, thank you very much!

@nick-youngblut
Copy link

nick-youngblut commented Feb 28, 2024

@pvictor after I add a new event, the event cannot be selected via my custom pop-up code for editing (no value for the new event in input$calendar_id_click$id).

I'm using cal_proxy_add() to add the new event, but it doesn't seem to create a new input$calendar_id_click$id value for the event. However, if I reload my app (and thus re-render the calendar), my newly added event is listed in input$calendar_id_click$id, so then it can be updated via my custom pop-up.

Any ideas on why input$calendar_id_click$id is not updated after creating a new event via a custom modal (as we discussed above)?

Note: it appears that calendar-custom-create.R also does not update input$calendar_id_click$id, given that if I add observeEvent(input$calendar_id_click, { print(input$calendar_id_click$id) }) to the app code, no click events occur when I click on events after creating them via the modal.

@pvictor
Copy link
Member

pvictor commented Feb 29, 2024

@nick-youngblut , @toxintoxin : can you please open new issues with some reproducible example ?

@pvictor pvictor closed this as completed Feb 29, 2024
@dreamRs dreamRs locked and limited conversation to collaborators Feb 29, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants