signalpoint / DrupalGap

An application development kit for Drupal websites.
https://www.drupalgap.org
GNU General Public License v2.0
232 stars 185 forks source link

offsetHieght and offsetWidth always 0 #1018

Closed tennist closed 5 years ago

tennist commented 5 years ago

My project uses the google maps plugin to display a map of locations. The latest version of this plugin checks the offsetWidth and offsetHeight of the div before initializing the map and makes sure they are both greater than 100. However, in drupalgap, this is being returned as 0 and 0. My initial thought is that the div is not fully rendered yet. However, shoudn't it already be rendered once we are in the pageshow callback? If not, how do we call a function in drupalgap after the page is completely loaded?

signalpoint commented 5 years ago

@tennist If you're adding your div in the page_callback, then yes it will be on the page before the pageshow. Maybe share your page_callback and pageshow implementations here for a look.

tennist commented 5 years ago

 * The find trails page callback.
 */
function big_trail_find_trails_map() {
  try {
    // Figure out the map's height from the device window height.
    var window_height = $(window).height();
    var map_height = window_height - 160; // = footer (px) + header (px)

    var content = {};
    var map_attributes = {
      id: 'big_trail_find_trails_map_map',
      style: 'width: 100%; height: ' + map_height + 'px;',
      visibility: 'visible'
    };
    content['map'] = {
      markup: '<div ' + drupalgap_attributes(map_attributes) + '></div>'
    };

    content['refresh_location'] = {
     theme: 'button',
     text: 'Refresh Map',
     attributes: {
      onclick: "big_trail_find_trails_refresh_button_click()",
      'data-theme': 'b'
     }   
    };

    return content;
  }
  catch (error) { console.log('big_trail_find_trails_map - ' + error); }
}

/**
 * The map pageshow callback.
 */
function big_trail_find_trails_map_pageshow() {

    // Build the lat lng object from the user's position.
          myLatlng = new plugin.google.maps.LatLng(
          _big_trail_user_latitude,
          _big_trail_user_longitude
        );  

    // Set the map's options.
        var mapOptions = {
          'controls': {
            'compass': true,
            'myLocationButton': true,           
            'zoom': true
          },
          'gestures': {
            'scroll': true,
            'tilt': true,
            'rotate': true,
            'zoom': true
          },
          'camera': {
            'latLng': myLatlng,         
            'zoom': 13          
          }

        };          

        // Initialize the map
        _big_trail_map = plugin.google.maps.Map.getMap(
          document.getElementById("big_trail_find_trails_map_map"),
          mapOptions
        );

        //Wait for the map to be ready then add markers to it
        _big_trail_map.one(plugin.google.maps.event.MAP_READY, function() {

            var htmlInfoWindow = new plugin.google.maps.HtmlInfoWindow();
            //Create the Address Div
            var address_div = '<div style="clear:both; overflow:auto;">' +
              '<div style="float:left;">' +
              '<b> Address: </b>' +
              '</div>' +
              '<div style="float:left; margin-left:5px;">' +
              '<a href="http://maps.google.com" target="_blank">Open the Google Maps</a>' +
              '</div>' +
              '</div>';

            // Add a marker for the user's current position.
            _big_trail_map.addMarker({
                position: myLatlng,            
                icon: 'app/modules/custom/big_trail/red-dot.png'
            }, function(marker) {
              marker.on(plugin.google.maps.event.MARKER_CLICK, function() {
                htmlInfoWindow.setContent(address_div);
                htmlInfoWindow.open(marker);
              });   

            });             
        }); 
}```
tennist commented 5 years ago

If I print the offsetHeight and offsetWidth of document.getElementById("big_trail_find_trails_map_map") to the console in the beginning of the pageshow function it returns 0 and 0

signalpoint commented 5 years ago

@tennist It looks like you may have a syntax error in your style definition. Try changing this:

style: 'width: 100%; height: ' + map_height + 'px;',
      visibility: 'visible'

to this:

style: 'width: 100%; height: ' + map_height + 'px;' +
      'visibility: visible'
tennist commented 5 years ago

I was just playing around with different attributes in different locations to try and get the map to work again after the latest release of the google maps plugin. I forgot to remove this line. The visibility attribute shouldn't be needed as it should be visible by default. My original code looked like so:


 * The find trails page callback.
 */
function big_trail_find_trails_map() {
  try {
    // Figure out the map's height from the device window height.
    var window_height = $(window).height();
    var map_height = window_height - 160; // = footer (px) + header (px)

    var content = {};
    var map_attributes = {
      id: 'big_trail_find_trails_map_map',
      style: 'width: 100%; height: ' + map_height + 'px;'     
    };
    content['map'] = {
      markup: '<div ' + drupalgap_attributes(map_attributes) + '></div>'
    };

    content['refresh_location'] = {
     theme: 'button',
     text: 'Refresh Map',
     attributes: {
      onclick: "big_trail_find_trails_refresh_button_click()",
      'data-theme': 'b'
     }   
    };

    return content;
  }
  catch (error) { console.log('big_trail_find_trails_map - ' + error); }
}

/**
 * The map pageshow callback.
 */
function big_trail_find_trails_map_pageshow() {

    // Build the lat lng object from the user's position.
          myLatlng = new plugin.google.maps.LatLng(
          _big_trail_user_latitude,
          _big_trail_user_longitude
        );  

    // Set the map's options.
        var mapOptions = {
          'controls': {
            'compass': true,
            'myLocationButton': true,           
            'zoom': true
          },
          'gestures': {
            'scroll': true,
            'tilt': true,
            'rotate': true,
            'zoom': true
          },
          'camera': {
            'latLng': myLatlng,         
            'zoom': 13          
          }

        };          

        // Initialize the map
        _big_trail_map = plugin.google.maps.Map.getMap(
          document.getElementById("big_trail_find_trails_map_map"),
          mapOptions
        );

        //Wait for the map to be ready then add markers to it
        _big_trail_map.one(plugin.google.maps.event.MAP_READY, function() {

            var htmlInfoWindow = new plugin.google.maps.HtmlInfoWindow();
            //Create the Address Div
            var address_div = '<div style="clear:both; overflow:auto;">' +
              '<div style="float:left;">' +
              '<b> Address: </b>' +
              '</div>' +
              '<div style="float:left; margin-left:5px;">' +
              '<a href="http://maps.google.com" target="_blank">Open the Google Maps</a>' +
              '</div>' +
              '</div>';

            // Add a marker for the user's current position.
            _big_trail_map.addMarker({
                position: myLatlng,            
                icon: 'app/modules/custom/big_trail/red-dot.png'
            }, function(marker) {
              marker.on(plugin.google.maps.event.MARKER_CLICK, function() {
                htmlInfoWindow.setContent(address_div);
                htmlInfoWindow.open(marker);
              });   

            });             
        }); 
}```

I have discussed this with the google maps plugin developer and no other platforms are having a problem with this new check on offsetHeight and offsetWidth of the map container.  He thinks the div is not yet fully rendered when the pageshow function is triggered and that is why offsetHeight and offsetWidth are returning a value of 0.  My code closely follow your example for creating an app with a map of locations so I was hoping you had run into this issue on your apps as well.
tennist commented 5 years ago

I wanted to verify that this is an issue with the div not being rendered yet so i created an additional button on the page for initializing the map. I then copied the pageshow code to this button click event function and the map generates as intended when the button is clicked.

So this verifies that the the page is not fully rendered when the pageshow event is triggered. Is there a way to trigger an event in drupalgap after the page is fully loaded?

signalpoint commented 5 years ago

@tennist Well technically the pageshow event is fired after the page is shown, but Google Maps in particular seems to battle with this. Maybe try wrapping all your code in your pageshow callback in a setTimeout like so:

function big_trail_find_trails_map_pageshow() 
  setTimeout(function() {

    // Add all your pageshow code in here...

  }, 100);
}
tennist commented 5 years ago

@signalpoint That is what was needed, however, it needed a 200ms delay to work. Thanks for your help and quick responses.