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

whole element hidden instead of element within label #153

Closed
fabiangehring opened this issue Feb 9, 2018 · 7 comments
Closed

whole element hidden instead of element within label #153

fabiangehring opened this issue Feb 9, 2018 · 7 comments

Comments

@fabiangehring
Copy link

fabiangehring commented Feb 9, 2018

In the following minimal example the complete selectizInput is hidden when klicked on the link (instead of only the link in the label).

library(shiny)
library(shinyjs)

ui <- fluidPage(
  tagList(
    shinyjs::useShinyjs(),
    selectizeInput(
      "select", 
      choices = LETTERS, 
      label = div("labeltext", actionLink("link", "linktext"))
    )
  )
)

server <- function(input, output, session) {
  observeEvent(input$link, {
    shinyjs::hide("link")
  })
}

shinyApp(ui, server)

Am I missing something here?

@daattali
Copy link
Owner

daattali commented Feb 9, 2018

Hm I know exactly why this happens, but unfortunately I can't think of a proper fix. I'll explain.

When you want to show/hide/enable/disable/etc an element using shinyjs, what shinyjs does is perform that action on the element you called BUT it also searches up the DOM tree to see if this element is inside a Shiny input container, and if it is, then the action is performed on the entire shiny input container.

The reason this has to happen is because for many shiny inputs, the actual ID is not the correct HTML element that you want to hide. Shiny constructs a container around the input that includes other things, and you want the entire input container to get hidden. For example, this is the HTML generated from the select input in your code:

image

If you look, in that HTML there is a tag with an id of select. Suppose you want to hide the select input, so you call hide("select"). If I just hide that element, nothing will happen. I have to climb up the tree to element with class shiny-input-container and hide that entire element in order to get the desired behaviour.

But in your case, you're trying to hide another element within the input, so it's an edge case where this behaviour is not desireable that has not come up yet.

I can't think of any good way to automatically know when I should hide the entire container and when I should not. I'm not sure if there is a possible way to know. I'll think about it some more.

If anyone has anything to contribute or any questions, feel free!

@daattali
Copy link
Owner

daattali commented Feb 9, 2018

After some investigation, it seems like I might have a solution. It's possible that every shiny input has a class of shiny-bound-input on it, so if that's true I can simply look for that info and based on that decide if to search for a container or not. I'll look into that when I can.

@fabiangehring
Copy link
Author

fabiangehring commented Feb 9, 2018

I see and was already expecting something like this. I was also toying a little with "selector" but wasn't able to get the desired result, my gut feeling tells me it should be doable with selector here?

In general. What about giving the user an extra option "findContainer" which defaults to TRUE?

@daattali
Copy link
Owner

daattali commented Feb 9, 2018

Even if you use a selector, I purposely always look up to see if there's an input container. What you want to do is strictly not possible currently (unless you want to create the label outside of the select input, and use css to make it look like it's inside...)

I did briefly think about adding such a parameter, but luckily I found the shiny-bound-input class which shows some promise. In general I'm very hesitant adding a new parameter and only want to do it if it's absolutely essential. Adding a new parameter will break the existing symmetry between hide/show/toggle, because it would have to go at the end of the parameter list (to not break existing people's code), which means that the condition parameter for toggle() will no longer be last after all the parameters of hide/show. I hope that makes sense.

@fabiangehring
Copy link
Author

Makes perfect sense. I guess adding a parameter shoud be the last solution. If shiny-bound-input works, great! Looking forward to it. Thanks again for a great package!

@daattali
Copy link
Owner

@fabiangehring I looked into this some more and did find a way to stop the current behaviour, so that only when you're trying to shoe/hide an actual shiny input it would search up the tree and hide the entire input container.

So something like this would work:

library(shiny)
library(shinyjs)

ui <- fluidPage(
    tagList(
        shinyjs::useShinyjs(),
        selectizeInput(
            "select", 
            choices = LETTERS, 
            label = div("labeltext", tags$a(id = "link", "linktext"))
        )
    )
)

server <- function(input, output, session) {
    shinyjs::onclick("link", shinyjs::hide("link"))
}

shinyApp(ui, server)

However, in your specific case, it would still hide the entire input, because an actionLink() does have the shiny-bound-input class because shiny treats it as an input, but it's a strange input because buttons and links do not have an input container. So with your code the same behaviour would happen. Does that make sense?

Technically it's possible to say "only if this element is an input BUT if it's not a button or a link, then search for the input container" but that's getting too assumptious and I'm not comfortable implementing such logic. I'm ok with getting non intended behaviour when placing an input inside an input.

@fabiangehring
Copy link
Author

That's great. For my case it's perfectly fine to do it with tags$a. Thank you very much.

@daattali daattali reopened this Mar 15, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants