Shinydashboard: Google Places Autocomplete. InvalidValueError: not an instance of HTMLInputElement

|▌冷眼眸甩不掉的悲伤 提交于 2019-12-11 01:07:49

问题


I am trying to put a shinydashboard together and have a Google Places Search box as a text input. The code below runs in a regular shiny page, but throws an InvalidValueError: not an instance of HTMLInputElement error when it's put into a shinydashboard. (See image below)

I'm not sure why it would work in a regular shiny app but not inside a shinydashboard.

Screenshot of error:

Minimal reproducible code example:

Note: Plug in your Google API key first

library(shiny)
library(googleway)
library(shinydashboard)

#key <- "MyKey"
#set_key(key = key)
#google_keys()


ui<- shinydashboard::dashboardPage(
  dashboardHeader(title = "Look @ Console"),
  dashboardSidebar(list(sidebarMenuOutput("sideBar_menu_UI"))), 
  dashboardBody(
    HTML(paste0(" <script> 
                 function initAutocomplete() {

                var autocomplete = new google.maps.places.Autocomplete(document.getElementById('my_address'),{types: ['geocode']});
                autocomplete.setFields(['address_components', 'formatted_address',  'geometry', 'icon', 'name']);
                autocomplete.addListener('place_changed', function() {
                var place = autocomplete.getPlace();
                if (!place.geometry) {
                return;
                }

                var addressPretty = place.formatted_address;
                var address = '';
                if (place.address_components) {
                address = [
                (place.address_components[0] && place.address_components[0].short_name || ''),
                (place.address_components[1] && place.address_components[1].short_name || ''),
                (place.address_components[2] && place.address_components[2].short_name || ''),
                (place.address_components[3] && place.address_components[3].short_name || ''),
                (place.address_components[4] && place.address_components[4].short_name || ''),
                (place.address_components[5] && place.address_components[5].short_name || ''),
                (place.address_components[6] && place.address_components[6].short_name || ''),
                (place.address_components[7] && place.address_components[7].short_name || '')
                ].join(' ');
                }
                var address_number =''
                address_number = [(place.address_components[0] && place.address_components[0].short_name || '')]
                var coords = place.geometry.location;
                //console.log(address);
                Shiny.onInputChange('jsValue', address);
                Shiny.onInputChange('jsValueAddressNumber', address_number);
                Shiny.onInputChange('jsValuePretty', addressPretty);
                Shiny.onInputChange('jsValueCoords', coords);});}
                </script> 
                <script src='https://maps.googleapis.com/maps/api/js?key=", key,"&libraries=places&callback=initAutocomplete' async defer></script>"))
    ,uiOutput("tabContentUI")
  )
)



server <- function(input, output) {

  output$sideBar_menu_UI <- renderMenu({
    sidebarMenu(id = "sideBar_Menu",

                menuItem("Data Import", tabName="datatab", icon = icon("database")),
                conditionalPanel("input.sideBar_Menu=='datatab'", 
                                 shiny::radioButtons(inputId = "upload_custom_data", label = "Do You Want To Upload Your Own Data?",
                                                     choices  = c("Yes"=TRUE, "No"=FALSE), selected = FALSE, inline = TRUE),
                                 shiny::uiOutput("conditionalFileInputUI")),
                menuItem("AnotherMenu", tabName = "anotherMenu", icon = icon("list-ol")))
  }) 

  output$conditionalFileInputUI<- shiny::renderUI({
    if(input$upload_custom_data == TRUE){}
    if(input$upload_custom_data == FALSE){
      list(
        shiny::textInput(inputId = "my_address", label = "Search For Address", width = "350px"),
        shiny::actionButton(inputId = "add_btn", label = "Add To Dataset", icon = icon("plus"))
      )

    }
  })

  ### Output$Stuff Here
  output$anotherMenu_content<- shiny::renderText({"This is some text" })
  output$datatab_content<- shiny::renderUI({ list(shiny::uiOutput("full_address"), shiny::uiOutput("my_map")) })

  #### Tab Content UI Materials
  output$tabContentUI<- shiny::renderUI({
    shinydashboard::tabItems(
      shinydashboard::tabItem(tabName = "datatab", shiny::uiOutput("datatab_content")), 
      shinydashboard::tabItem(tabName = "anotherMenu", shiny::textOutput("anotherMenu_content"))
    )
  })

  my_address <- reactive({
    if(!is.null(input$jsValueAddressNumber)){
      if(length(grep(pattern = input$jsValueAddressNumber, x = input$jsValuePretty ))==0){
        final_address<- c(input$jsValueAddressNumber, input$jsValuePretty)
      } else{
        final_address<- input$jsValuePretty
      }
      final_address
    }
  })

  output$full_address <- renderText({
    if(!is.null(my_address())){
      paste0("The Fuller and Fixed Address is... ", my_address())
    }
  })

  output$my_map <- renderGoogle_map({
    my_address <- my_address()
    shiny::validate(
      need(my_address, "Address not available")
    )

    gdat <- google_geocode(address = my_address)
    my_coords <- geocode_coordinates(gdat)
    my_coords <- c(my_coords$lat[1], my_coords$lng[1])

    google_map(
      location = my_coords,
      zoom = 12,
      map_type_control = FALSE,
      zoom_control = FALSE,
      street_view_control = FALSE
    )
  })

}

shinyApp(ui, server)

I'm curious to know if anyone has an idea as to how this can be fixed? I'm grateful for any feedback. Thank you in advance.

--nate

Update:

I still have not solved this problem. But, through trial and error, I've noticed I can get some functionality back if I take the 'Search For Address' input out of the server.R file and put raw HTML in the UI part.

Putting this code into the UI gets a partial solution going...(apologies for formatting)

  shinydashboard::dashboardSidebar(width = "400px",


list(shinydashboard::sidebarMenuOutput(outputId = "sideBar_menu_UI"),


 HTML('<div class="form-group shiny-input-container"> <label for="my_address">Type An Address</label> <input id="my_address" type="text" class="form-control" value=""/> </div>'))),

The Updated UI now looks like this:


回答1:


The only way I have been able to do this is by taking all the logic behind rendering the sidebarMenu out of the server.R file and putting it into the ui.R file.

The final working solution is this:

library(shiny)
library(googleway)
library(shinydashboard)

#key <- "MyKey"
#set_key(key = mygoogleapikey)
#google_keys()


ui<- shinydashboard::dashboardPage(
  dashboardHeader(title = "This Works"),
  dashboardSidebar(shinydashboard::sidebarMenu(id="sideBar_Menu",
                                              menuItem("Data Import", tabName="datatab", icon = icon("database")),
                                              conditionalPanel("input.sideBar_Menu=='datatab'",
                                              shiny::radioButtons(inputId = "upload_custom_data", label = "Do You Want To Upload Your Own Data?", choices  = c("Yes"=TRUE, "No"=FALSE), selected = TRUE, inline = TRUE),

                                              conditionalPanel("input.upload_custom_data == 'TRUE'",
                                                               shiny::actionButton("go", "Go")),

                                              conditionalPanel("input.upload_custom_data == 'FALSE'",
                                                               textInput(inputId = "my_address", label = "Type An Address"),
                                                               shiny::actionButton(inputId = "add_btn", label = "Add To Dataset", icon = icon("plus")))


                                               ), # with outer conditional menu
                                               menuItem("AnotherMenu", tabName = "anotherMenu", icon = icon("list-ol"))
  ) # with sidebar menu
  ),

  dashboardBody(
    HTML(paste0(" <script> 
                function initAutocomplete() {

                var autocomplete = new google.maps.places.Autocomplete(document.getElementById('my_address'),{types: ['geocode']});
                autocomplete.setFields(['address_components', 'formatted_address',  'geometry', 'icon', 'name']);
                autocomplete.addListener('place_changed', function() {
                var place = autocomplete.getPlace();
                if (!place.geometry) {
                return;
                }

                var addressPretty = place.formatted_address;
                var address = '';
                if (place.address_components) {
                address = [
                (place.address_components[0] && place.address_components[0].short_name || ''),
                (place.address_components[1] && place.address_components[1].short_name || ''),
                (place.address_components[2] && place.address_components[2].short_name || ''),
                (place.address_components[3] && place.address_components[3].short_name || ''),
                (place.address_components[4] && place.address_components[4].short_name || ''),
                (place.address_components[5] && place.address_components[5].short_name || ''),
                (place.address_components[6] && place.address_components[6].short_name || ''),
                (place.address_components[7] && place.address_components[7].short_name || '')
                ].join(' ');
                }
                var address_number =''
                address_number = [(place.address_components[0] && place.address_components[0].short_name || '')]
                var coords = place.geometry.location;
                //console.log(address);
                Shiny.onInputChange('jsValue', address);
                Shiny.onInputChange('jsValueAddressNumber', address_number);
                Shiny.onInputChange('jsValuePretty', addressPretty);
                Shiny.onInputChange('jsValueCoords', coords);});}
                </script> 
                <script src='https://maps.googleapis.com/maps/api/js?key=", key,"&libraries=places&callback=initAutocomplete' async defer></script>"))
    ,uiOutput("tabContentUI")
    )
    )



server <- function(input, output) {




  ### Output$Stuff Here
  output$anotherMenu_content<- shiny::renderText({"This is some text" })
  output$datatab_content<- shiny::renderUI({ list(shiny::uiOutput("full_address"), shiny::uiOutput("my_map")) })

  #### Tab Content UI Materials
  output$tabContentUI<- shiny::renderUI({
    shinydashboard::tabItems(
      shinydashboard::tabItem(tabName = "datatab", shiny::uiOutput("datatab_content")), 
      shinydashboard::tabItem(tabName = "anotherMenu", shiny::textOutput("anotherMenu_content"))
    )
  })

  my_address <- reactive({
    if(!is.null(input$jsValueAddressNumber)){
      if(length(grep(pattern = input$jsValueAddressNumber, x = input$jsValuePretty ))==0){
        final_address<- c(input$jsValueAddressNumber, input$jsValuePretty)
      } else{
        final_address<- input$jsValuePretty
      }
      final_address
    }
  })

  output$full_address <- renderText({
    if(!is.null(my_address())){
      paste0("The Fuller and Fixed Address is... ", my_address())
    }
  })

  output$my_map <- renderGoogle_map({
    my_address <- my_address()
    shiny::validate(
      need(my_address, "Address not available")
    )

    gdat <- google_geocode(address = my_address)
    my_coords <- geocode_coordinates(gdat)
    my_coords <- c(my_coords$lat[1], my_coords$lng[1])

    google_map(
      location = my_coords,
      zoom = 12,
      map_type_control = FALSE,
      zoom_control = FALSE,
      street_view_control = FALSE
    )
  })

}

shinyApp(ui, server)


来源:https://stackoverflow.com/questions/54848254/shinydashboard-google-places-autocomplete-invalidvalueerror-not-an-instance-o

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!