IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    Introducing Autocomplete Search to shiny.fluent’s Dropdown Component

    Tresna Tanesya发表于 2023-12-18 07:30:55
    love 0
    [This article was first published on Tag: r - Appsilon | Enterprise R Shiny Dashboards, and kindly contributed to R-bloggers]. (You can report issue about the content on this page here)
    Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.

    The introduction of shiny.react has been a significant milestone in R Shiny’s evolution, acting as a bridge to React.js and enabling the incorporation of React components within Shiny applications. shiny.fluent, leveraging shiny.react, integrates Microsoft’s Fluent UI components into Shiny, broadening the scope for UI design and functionality.

    In a recent one-hour hackathon, we set out to explore the potential of shiny.react and shiny.fluent in delivering a customized user interface of a Shiny application. Our primary focus was integrating an autocomplete search feature into the Dropdown element of shiny.fluent.

    In this article, we will explore the outcome of our hackathon and how you can implement it in your projects.

    Table of Contents

    • The Challenge
    • Leveraging shiny.react for Seamless Integration
    • Conclusion

    The Challenge

    The Dropdown component, a part of Fluent UI exposed by the shiny.fluent package, stands out for its functionality and reliability. Yet, when users encounter long lists of options, navigating through them can be less than optimal.

    To enhance this experience, we aimed to integrate an autocomplete search box within the Dropdown.This feature is designed to streamline the process, allowing users to quickly search and filter through the extensive list of options.

    It’s noteworthy that shiny.fluent also exposes Fluent UI’s ComboBox, a component with built-in autocomplete functionality. However, our focus was different; we wanted to specifically enhance the Dropdown component by adding a search box that not only allows for searching but also filters the available options in real-time.

    Interested in enhancing the user experience of your Shiny apps while optimizing handling of large datasets? Explore how our latest reactable.extras release can help you.

    Leveraging shiny.react for Seamless Integration

    Our breakthrough came when we discovered a React code snippet that perfectly suited our needs. This code provided a foundation for adding an autocomplete search functionality to the dropdown menu. The key task was adapting this React code to work seamlessly within our Shiny application.

    Here’s how we started by creating a basic Dropdown with a variety of fruit and vegetable options:

    box::use(
    shiny[div, moduleServer, NS, observeEvent],
    shiny.fluent[JS, fluentPage, Dropdown.shinyInput],
    )
    
    #' @export
    ui <- function(id) {
    ns <- NS(id)
    fluentPage(
      div(
        style = "height: 100%; width: 50%; margin:auto",
        Dropdown.shinyInput(
          inputId = ns("fruit"),
          label = "Searchable Fruit Selector",
          multiSelect = TRUE,
          placeholder = "Fruit/Vegetable",
          options = list(
            list(key = "apple", text = "Apple"),
            list(key = "banana", text = "Banana"),
            list(key = "orange", text = "Orange"),
            list(key = "grape", text = "Grape"),
            list(key = "broccoli", text = "Broccoli"),
            list(key = "carrot", text = "Carrot"),
            list(key = "lettuce", text = "Lettuce")
           )
         )
       )
     )
    }
    
    #' @export
    server <- function(id) {
    moduleServer(id, function(input, output, session) {
      observeEvent(input$fruit, {
        print(input$fruit)
      })
    })
    }
    
    searchable fruit selector

    Searchable Fruit Selector

    We then added a filtering header using the SearchBox in the options list:

    DropdownMenuItemType <- function(type) { # nolint
     JS(paste0("jsmodule['@fluentui/react'].DropdownMenuItemType."), type)
    }
    // Add __FilterHeader__ to Dropdown’s options
    ui <- function(id) {
     ns <- NS(id)
     fluentPage(
       div(
         style = "height: 100%; width: 50%; margin:auto",
         Dropdown.shinyInput(
           ...,
           options = list(
             list(key = "__FilterHeader__", text = "-", itemType = DropdownMenuItemType("Header")),
            ...
            )
          )
        )
      )
    }
    

    Finally, thanks to shiny.fluent exposing Fluent UI’s properties, we could customize our Dropdown with the onRenderOption prop.

    This allowed us to tailor a custom renderer for the dropdown options:

    render_search_box <- JS(paste("(option) => {
      // if option is not the header, simply return option label
      if (option.key !== '__FilterHeader__') {
        return option.text;
      }
    
      // handle onChange event
      const onChange = (event, newValue) => {
        // get the typed key in lowercase
        const query = newValue.toLocaleLowerCase();
    
        // get the checkbox labels
        const checkboxLabels = document.querySelectorAll(
          'div.ms-Checkbox .ms-Checkbox-label'
        );
    
        // filter options according to search
        checkboxLabels.forEach(label => {
          const text = label.innerText.replace('\\n', '').replace('', '').toLocaleLowerCase();
    
          // if the label of the option does not start with the typed search, we hide it
          if (query === '' || text.startsWith(query)) {
            label.parentElement.style.display = 'flex';
          } else {
            label.parentElement.style.display = 'none';
          }
        });
      };
    
      // finally, create the react element
      const props = { placeholder: 'Start typing', underlined: true, onChange };
      const element = React.createElement(jsmodule['@fluentui/react'].SearchBox, props)
      return element;
    }"))
    
    // Add onRenderOption prop
    ui <- function(id) {
     ns <- NS(id)
     fluentPage(
       div(
         style = "height: 100%; width: 50%; margin:auto",
         Dropdown.shinyInput(
           ...,
           onRenderOption = render_search_box
          )
        )
      )
    }
    

    If you’re keen on exploring the project’s implementation in detail, you can find the complete code available in the Gist below:

    Conclusion

    As our one-hour hackathon concludes, we’ve successfully integrated an autocomplete search feature into the shiny.fluent Dropdown component, demonstrating a practical application of shiny.react and shiny.fluent in enhancing Shiny UIs.

    Looking ahead, we see opportunities to refine this feature, especially in terms of accessibility and user experience. For instance, improving keyboard interactions, such as enabling more intuitive navigation and selection within the dropdown, could be a valuable enhancement.

    Did you find this helpful? Leave us a comment and join us for R Shiny Trivia Night at our next Shiny Gathering! Test your knowledge, meet fellow enthusiasts, and enjoy a night of fun and networking. Secure your spot for this exciting trivia event today!

    The post appeared first on appsilon.com/blog/.

    To leave a comment for the author, please follow the link and comment on their blog: Tag: r - Appsilon | Enterprise R Shiny Dashboards.

    R-bloggers.com offers daily e-mail updates about R news and tutorials about learning R and many other topics. Click here if you're looking to post or find an R/data-science job.
    Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.
    Continue reading: Introducing Autocomplete Search to shiny.fluent’s Dropdown Component


沪ICP备19023445号-2号
友情链接