The highlight_row function seems to be delayed, as it does not trigger on the initial onClick but works on subsequent clicks. How can I ensure it works properly right from the first click?

I developed an application using the Google JavaScript Maps API to calculate distances between addresses. I've encountered a bug where the row in the table is not highlighted on the first click, requiring a second click for the highlighting to take effect when calling the function highlight_row().

I have tried adding the highlight_row() function to the global scope and calling it separately in the onClick event, but it still doesn't style the row on the first click. Any suggestions or assistance on why this behavior occurs would be highly appreciated. Thank you.

Additionally, I attempted adding the onclick event inside the span element of the table cell, and it only triggers when the display name cell is clicked. Surprisingly, adding onClick in the span successfully styles the selected row on the first click. What could be the reason behind this difference in behavior when placed in different tags?

Below, I will provide the code snippet for reference. To test locally, please insert your own Google Maps API key.

<!DOCTYPE html>
<!-- Rest of the HTML code remains the same -->
</body>
</html>

Answer №1

If I were to optimize the original code by removing inline function calls and utilizing externally registered event handlers, it could potentially improve efficiency. The current SetTourLocationRecordId function seems to have limited utility with the data it receives. Therefore, an alternative approach outlined below may offer more value.

<!DOCTYPE html>
<html>
  <head>
    <title>Distance Calculation</title>

    <style>
      table {
        border-collapse: collapse;
        width: 100%;
      }

      th,
      td {
        border: 1px solid #ddd;
        padding: 8px;
        text-align: left;
      }

      th {
        background-color: #f2f2f2;
      }

      tr.highlighted {
        background-color: blue;
        color: white; /* For better visibility */
      }
      
      label,input,button{padding:0.25rem}
      
      /* custom class to add to highlighted table rows... probably same as above? */
      .row_highlight{
        background:#1e90ff;
        color:snow;
      }
    </style>
    <script>
      const destinationAddresses = {
        destination1: {
          Tour_Location: "Embassy Suites by Hilton Parsippany",
          Display_Name: "Hilton Parsippany",
          Address1: "909 Parsippany Blvd",
          Address2: "",
          City: "Parsippany",
          State: "NJ",
          Zip: "07054",
          Tour_Location_Record_Id: "a1F1U000003VKSSUA4",
          Phone: "(631) 260-1849",
        },
        destination2: {
          Tour_Location: "Roosevelt Field Mall",
          Display_Name: "Roosevelt Field Mall",
          Address1: "2nd Floor - Next to Nordstrom",
          Address2: "630 Old Country Rd",
          City: "Garden City",
          State: "NY",
          Zip: "11530",
          Tour_Location_Record_Id: "a1F1U000003UG8NUAW",
          Phone: "(631) 260-1849",
        },
        destination3: {
          Tour_Location: "Club Wyndham Midtown 45",
          Display_Name: "Midtown 45",
          Address1: "205 E 45th St",
          Address2: "",
          City: "New York",
          State: "NY",
          Zip: "10017",
          Tour_Location_Record_Id: "a1F1U000003UbX8UAK",
          Phone: "(555) 555-5555",
        },
        // Add more destination objects if needed
      };
      
      
      
      
      
      function init(){
        const geocoder = new google.maps.Geocoder(); // only need to declare this once!</answer1>
<exanswer1><div class="answer" i="76913394" l="4.0" c="1692176785" a="UHJvZmVzc29yIEFicm9uc2l1cw==" ai="3603681">
<p>I would be tempted to modify the original code slightly as below to remove inline function calls and instead use externally registered event handlers. It seems that your <code>SetTourLocationRecordId does lots of things but nothing really useful is done with the data passed in so an alternative approach below might be of interest.

<!DOCTYPE html>
<html>
  <head>
    <title>Distance Calculation</title>

    <style>
      table {
        border-collapse: collapse;
        width: 100%;
      }

      th,
      td {
        border: 1px solid #ddd;
        padding: 8px;
        text-align: left;
      }

      th {
        background-color: #f2f2f2;
      }

      tr.highlighted {
        background-color: blue;
        color: white; /* For better visibility */
      }
      
      label,input,button{padding:0.25rem}
      
      /* custom class to add to highlighted table rows... probably same as above? */
      .row_highlight{
        background:#1e90ff;
        color:snow;
      }
    </style>
    <script>
      const destinationAddresses = {
        destination1: {
          Tour_Location: "Embassy Suites by Hilton Parsippany",
          Display_Name: "Hilton Parsippany",
          Address1: "909 Parsippany Blvd",
          Address2: "",
          City: "Parsippany",
          State: "NJ",
          Zip: "07054",
          Tour_Location_Record_Id: "a1F1U000003VKSSUA4",
          Phone: "(631) 260-1849",
        },
        destination2: {
          Tour_Location: "Roosevelt Field Mall",
          Display_Name: "Roosevelt Field Mall",
          Address1: "2nd Floor - Next to Nordstrom",
          Address2: "630 Old Country Rd",
          City: "Garden City",
          State: "NY",
          Zip: "11530",
          Tour_Location_Record_Id: "a1F1U000003UG8NUAW",
          Phone: "(631) 260-1849",
        },
        destination3: {
          Tour_Location: "Club Wyndham Midtown 45",
          Display_Name: "Midtown 45",
          Address1: "205 E 45th St",
          Address2: "",
          City: "New York",
          State: "NY",
          Zip: "10017",
          Tour_Location_Record_Id: "a1F1U000003UbX8UAK",
          Phone: "(555) 555-5555",
        },
        // Add more destination objects if needed
      };
      
      
      
      
      
      function init(){
        const geocoder = new google.maps.Geocoder(); // only need to declare this once!
        const getAddress=(o)=>`${o.Address1} ${o.Address2}, ${o.City}, ${o.State} ${o.Zip}`;
        
        /*
            What does this function actually do???
        */      
        const SetTourLocationRecordId=(e)=>{
            const json=JSON.parse( e.target.closest('tr').dataset.json );
            if( Object.keys( json ).length > 0 ){
                Object.keys( json ).forEach(key=>{
                    console.log( 'Key:%s, Value:%s',key, json[key] )
                });
            }
        };
        const highlight_row=(e)=>{
            let table=e.target.closest('table');// find the parent table from the click event target
            table.querySelectorAll('tr').forEach(tr=>{//remove assigned className from each table-row
                tr.classList.remove('row_highlight');
            });
            e.target.closest('tr').classList.add('row_highlight')// add chosen className to this table row
        };
        /* 
            define an event handler - this enables us to remove it. 
            You could do this in other ways but this is relatively clean.
        */
        const tableclickhandler=(e)=>{
            if( e.target!=e.currentTarget && e.target instanceof HTMLTableCellElement ){
                SetTourLocationRecordId(e);
                highlight_row(e);
            }
        }

        function calculateDistance() {
            const address1 = document.querySelector('input[name="address"]').value;
            const div=document.getElementById('result');
            

            geocoder.geocode({ address: address1 }, function (results1, status1) {
              if (status1 === google.maps.GeocoderStatus.OK) {
                const origin = results1[0].geometry.location;
                const distanceService = new google.maps.DistanceMatrixService();
                
                distanceService.getDistanceMatrix(
                  {
                    origins: [origin],
                    destinations: Object.values(destinationAddresses).map(
                      (destination) => getAddress(destination)
                    ),
                    travelMode: google.maps.TravelMode.DRIVING,
                    unitSystem: google.maps.UnitSystem.IMPERIAL, // Use miles
                  },
                  function (response, status) {
                    if( status === google.maps.DistanceMatrixStatus.OK ) {
                        
                      // remove the click handler to prevent multiple firings of the code.
                      div.removeEventListener('click',tableclickhandler)
                        
                      let resultHtml = "<table id='display-table'>";
                          resultHtml +=`<tr>
                                <th>Display Name</th>
                                <th>City</th>
                                <th>State</th>
                                <th>Zip</th>
                                <th>Distance</th>
                                <th>Drive Time</th>
                            </tr>`;
                        
                        
                      for( const key in destinationAddresses ) {
                        if( destinationAddresses.hasOwnProperty(key) ) {
                          const destination = destinationAddresses[key];
                          const address = getAddress( destination );
                          const distance = response.rows[0].elements[ parseInt( key.split("destination")[1] ) - 1 ].distance.text;
                          const duration = response.rows[0].elements[ parseInt( key.split("destination")[1] ) - 1 ].duration.text;
                          /*
                          
                            Rather than adding each item as a parameter to the SetTourLocationRecordId
                            function you could simply supply the destination as a JSON string as a 
                            dataset attribute.
                            
                            Within the SetTourLocationRecordId function you can then access that dataset value
                            - though the original did nothing useful as far as I could see other than call the
                            highlight_row function. That highlight_row function has been simplified and uses
                            a className/classList rather than inline styles.
                            
                          */
                          
                          const json=JSON.stringify( destination );
                          
                          
                          
                          resultHtml += `
                            <tr data-json='${json}'>
                                <td><span>${destination.Display_Name}</span></td>
                                <td>${destination.City}</td>
                                <td>${destination.State}</td>
                                <td>${destination.Zip}</td>
                                <td>${distance}</td>
                                <td>${duration}</td>
                            </tr>`;
                        }
                      }
                      resultHtml += "</table>";
                      
                      if( resultHtml ) {
                      
                        div.innerHTML = resultHtml;
                        div.addEventListener('click',tableclickhandler )
                        
                      } else {
                        div.innerHTML = "Unable to calculate distance for all addresses.";
                      }
                      
                      

                      
                    } else {
                      div.innerHTML = "Error calculating distance.";
                    }
                  }
                );
              } else {
                div.innerHTML = "Invalid origin address.";
              }
            });
          }  
      
        document.querySelector('button[name="calc"]').addEventListener('click',calculateDistance );
      }
    </script>
  </head>
  <body>
  
    <h1>Distance Calculation</h1><!-- hardcoded address for testing only -->
    <label>Origin Address: <input type='text' name='address' value='Veterans Memorial Park, 1839 US-46, Parsippany, NJ 07054, United States' /></label>
    <button name='calc'>Calculate Distance</button>
    <div id='result'></div>
    
    <script async defer src='//maps.googleapis.com/maps/api/js?key=AIzaSy...&libraries=places&callback=init'></script>
  </body>
</html>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Angular 2 partial static routing parameters with customizable features

Can an angular 2 routing configuration include a partial-static parameter? Currently, I am using a classic parameter setup like this: const routes: Routes = [ { path: ':type/fine.html', pathMatch: 'full', redirectTo: &ap ...

Is there a way to set the size of my unique carousel design?

Having some trouble with my modal image carousel; the dimensions keep shifting for different image sizes. Image 1 Image 2 ...

The functionality of a Google chart is determined by the value of the AngularJS $scope

I recently started working with AngularJS and Google charts. I've successfully created a Google chart using data from AngularJS. It's functioning properly, but now I want to make the chart dynamic based on my Angular Scope value. I have a filter ...

Is it possible to utilize Mouse hover to distinguish between various elements in React?

In an attempt to enhance this code, I wanted to make it so that when you hover over a specific element, another related element would also be displayed. Using useState in React seemed to be the most effective way to accomplish this after trying out a diffe ...

Refine results by searching through the text contained in the elements of every div

I recently came across a helpful fiddle that allows text to be hidden based on what is entered into a search box. However, I am struggling to apply this method to a div that contains multiple elements. Is there a way to modify the jQuery in the provided fi ...

The controls for the HTML audio component are missing the download option on Safari

In my React application, I've declared an audio component with controls like the following: <audio controls> <source src={url} /> </audio> While this setup works perfectly in most browsers, it seems to have a bug when used in Safa ...

Having trouble centering the image position in Next JS using tailwind, need some assistance

Hey there, I'm currently working on a project that involves using next js and tailwind css. I am facing an issue where I am trying to center an image, but it seems like next js is not responding to the flex and justify-center properties as shown in th ...

Production environment experiencing issues with jQuery tabs functionality

Currently, I have implemented jQuery tabs on a simple HTML page. The tabs are functioning correctly and smoothly transitioning between different content sections. However, upon integrating this setup into my actual project environment, I encountered an is ...

The SyntaxError message indicates that there was an unexpected non-whitespace character found after the JSON data when parsing it

I received an Error message: SyntaxError: JSON.parse: unexpected non-whitespace character after JSON data Here is the code snippet: <script> $(document).ready(function () { $('.edit1').on('change', function () { ...

Is there a CSS rule that can alter the appearance of links once they have been clicked on a different webpage?

Just starting out here. Imagine I have 4 distinct links leading to the same webpage - is there a way to modify the properties of the destination page depending on which link was clicked? For instance, clicking on link1 changes the background color of the d ...

Accessing Drawer from a separate source file (Material-UI, React)

I'm facing a challenge trying to open a drawer in the "dashboard" file from the "Navbar" file. Essentially, I want to trigger the opening of the drawer located in the dashboard file from the navbar. It seems straightforward, but for some reason, I can ...

How can I retrieve the selected items from a Listbox control?

Currently, I am working on an ASP.NET application using C#. One of the features in my project involves a Grid View with a Listbox control. The Listbox is initially set to be disabled by default. My goal is to enable and disable this control dynamically bas ...

Sharing stickers with Discord.js version 13

I have encountered an issue while trying to forward messages sent to my bot via DM. Everything is functioning smoothly, except for sending stickers. Whenever I attempt to send a message with a sticker, an Error DiscordAPIError: Cannot use this sticker is ...

retrieving a JSON attribute that requires an additional HTTP call

Greetings, I have a dilemma related to Angular and a JSON file that I would like to share. Here is a snippet of the JSON data: { "users": [ { "gender": "male", "title": "mr", "first": "francisco", "last": "medina", "street": "2748 w dallas st", "c ...

Google Charts is unable to display any data because the table does not contain

After browsing numerous forums and attempting various solutions, I encountered a new challenge each time. My goal is to generate a Google line chart using data from a MYSQL table and encoding it in JSON. Then, I aim to utilize an HTML file to showcase the ...

Enhancing Material UI datepicker with custom CSS styles, including cursor pointer effects

I am facing an issue with my Material UI datepicker component in React. The cursor is not showing and the icon I added is not clickable, resulting in the datepicker dialog not appearing. Despite trying inline styling and styled-components, I have been una ...

How come the gridApi.on.edit.beginCellEdit function in angular-ui-grid does not immediately refresh the dropdown options after being updated?

I am encountering a similar issue as described in this post Regarding the assignment of ui grid value drop-down box before beginCellEdit event fires in Angular However, I have noticed a slight difference. Even after updating the editDropdownOptionArray, th ...

Creating a centered and beautifully styled picture with a specific maximum size using React

I recently completed the development of a new website, which can be viewed at Upon inspection of the website, it is evident that the photo is not centered and appears too large on mobile phones. Despite my efforts to align it using various methods outline ...

Finding the Xpath for an element that contains only a span tag, with identical attributes except for the text within

I am struggling to find the xpath for a button element that says 'Cancel'. <div class="uipresk"> <button class="something" role="button" type="button"> <span class="thisthing">OK</span> </button> ...

In the domain of React and Typescript, a minimum of '3' arguments is anticipated; nonetheless, the JSX factory 'React.createElement' is only equipped with a maximum of '2' arguments. This incongruity is signaled by the

I am facing an error with this particular component: const TheBarTitle = ( theClass: any, columnTitle: string, onClickAction: any, ) => { return ( <div className={theClass} title="Click to add this ...