Skip to content Skip to sidebar Skip to footer

Google Places Autocomplete, How To Clean Up Pac-container?

I'm using the google places autocomplete control, and it creates an element for the drop down with a class pac-container. I'm using the autocomplete in an ember app, and when I'm

Solution 1:

I was having the same problem, and hopefully Google eventually provides an official means of cleanup, but for now I was able to solve the problem by manually removing the pac-container object, a reference to which can be found in the Autocomplete class returned from:

var autocomplete = new google.maps.places.Autocomplete(element, options);

The reference to the pac-container element can be found at:

autocomplete.gm_accessors_.place.Mc.gm_accessors_.input.Mc.L

Which I simply removed from the DOM in my widget destructor:

$(autocomplete.gm_accessors_.place.Mc.gm_accessors_.input.Mc.L).remove();

Hope this helps.


Update

I'm not sure how Google's obfuscation works, but parts of the above seem obfuscated, and obviously will fail if the obfuscation or internal structures of the API change. Can't do much about the latter, but for the former you could at least search the object properties by expected criteria. As we can see, some of the property names are not obfuscated, while some appear to be, such as "Mc" and "L". To make this a little more robust, I wrote the following code:

var obj = autocomplete.gm_accessors_.place;
$.each(Object.keys(obj), function(i, key) {
  if(typeof(obj[key]) == "object" && obj[key].hasOwnProperty("gm_accessors_")) {
    obj = obj[key].gm_accessors_.input[key];
    returnfalse;
  }
});
$.each(Object.keys(obj), function(i, key) {
  if($(obj[key]).hasClass("pac-container")) {
    obj = obj[key];
    returnfalse;
  }
});
$(obj).remove();

The code expects the general structure to remain the same, while not relying on the (possibly) obfuscated names "Mc" and "L". Ugly I know, but hopefully Google fixes this issue soon.

Solution 2:

My implementation of code from above without jquery.

var autocomplete = new google.maps.places.Autocomplete(element, options);

exportfunctiongetAutocompletePacContainer(autocomplete) {
 constplace: Object = autocomplete.gm_accessors_.place;

 const placeKey = Object.keys(place).find((value) => (
    (typeof(place[value]) === 'object') && (place[value].hasOwnProperty('gm_accessors_'))
 ));

 const input = place[placeKey].gm_accessors_.input[placeKey];

 const inputKey = Object.keys(input).find((value) => (
   (input[value].classList && input[value].classList.contains('pac-container'))
 ));

 return input[inputKey];
}

getAutocompletePacContainer(autocomplete).remove()

Solution 3:

This works for now until Google changes the class name.

autocomplete.addListener('place_changed', function() {

    $('.pac-container').remove();

});

Solution 4:

Built this recursive function to locate element position inside autocomplete object.


Get first matching object

var elementLocator = function(prop, className, maxSearchLevel, level) {

    level++;

    if (level === (maxSearchLevel + 1) || !prop || !(Array.isArray(prop) || prop === Object(prop))) {
        return;
    }

    if (prop === Object(prop) && prop.classList && prop.classList.contains && typeof prop.classList.contains === 'function' && prop.classList.contains(className)) {
        return prop;
    }

    for (const key in prop) {
        if (prop.hasOwnProperty(key)) {
            var element = elementLocator(prop[key], className, maxSearchLevel, level);
            if (element) {
                return element;
            }
        }
    }
};

Usage:

var elm = null;
try {
    //set to search first 12 levels, pass -1 to search all levels
    elm = elementLocator(this.autocomplete, 'pac-container', 12, null); 
} catch(e) {
    console.log(e);
}

Solution 5:

I just encountered this issue as well. It may have something to do with my input field being inside of a flexbox but I haven't tried restructuring my page yet. Instead I added an onfocus listener to my input field as well as an onscroll listener to it's container. Inside I get the input field's position with getBoundingClientRect and then update my stylesheet with the values. I tried directly selecting and updating the .pac-container via document.querySelctor but that didn't seem to work. You may need a setTimeout to allow it to be added to the DOM first.

Here is my code:

let ruleIndex = null;
const form = document.body.querySelector('.form');
const input = document.body.querySelector('.form-input');

constpositionAutoComplete = () => {
  const { top, left, height } = inputField.getBoundingClientRect();
  if(ruleIndex) document.styleSheets[0].deleteRule(ruleIndex);
  ruleIndex = document.styleSheets[0].insertRule(`.pac-container { top: ${top + height}px !important; left: ${left}px !important; }`);
}

form.addEventListener('scroll', positionAutoComplete);
input.addEventListener('focus', positionAutoComplete);

As mentioned in an earlier answer, this breaks the minute google decides to rename .pac-container so not a perfect fix but works in the meantime.

Post a Comment for "Google Places Autocomplete, How To Clean Up Pac-container?"