From 3fd1f7711832e7902f463f1bb1c00f7aefddd666 Mon Sep 17 00:00:00 2001 From: Jocelyn Menard Date: Thu, 4 Apr 2024 14:13:05 -0400 Subject: [PATCH 1/2] feat: Fix error when GooglePlace return partial data, added a way to skip input autofil if not present and added a way to autofil select --- README.md | 5 +- public/js/widgets/address-autocomplete.js | 46 +++++++++++++++---- src/Api/GooglePlaces/Model/Address.php | 18 ++++++-- src/Form/Type/AddressAutocompleteType.php | 2 + templates/form/address_autocomplete.html.twig | 2 +- 5 files changed, 57 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index 8204b33..718c437 100644 --- a/README.md +++ b/README.md @@ -87,7 +87,7 @@ class MyFormType extends AbstractType 'entry_type' => AddressType::class, 'entry_options' => [ 'data_class' => Address::class, - 'api' => 'addressComplete', + 'api' => 'addressComplete', ], 'by_reference' => false, ]) @@ -104,6 +104,7 @@ Pour utiliser le champ `AddressAutocompleteType` dans vos `FormType`, vous devez 3. Ajouter les paramètres désirés: 1. Il est recommandé de désactiver l'autocomplete du champ pour éviter que les propositions du navigateur passent par-dessus les propositions d'autocomplete. Vous n'avez qu'à ajouter l'attribut suivant au champ: `'autocomplete' => uniqid('noautocomplete')`. 2. Il est possible de passer un paramètre `api` pour choisir l'API à utiliser. Les choix disponibles sont: `addressComplete` ou `googlePlaces`. Si aucun API est spécifié, l'api de Poste Canada "Address Complete" sera utilisé par défaut. + 3. Ajouter, au besoin l'option `parent` qui sert à définir un sélecteur JS valide qui sera utilisé à la place du `parentNode`. Utile si vous voulez remplir les informations de l'autocomplete sur des champs qui ne sont pas à l'intérieur du parent immédiat. Exemple: `.section-wrapper.geo.card` Voici un exemple: ```php @@ -124,6 +125,8 @@ class AddressType extends AbstractType 'autocomplete' => uniqid('noautocomplete'), ], 'api' => 'addressComplete', // addressComplete || googlePlaces + 'parent' => '.section-wrapper.geo.card', // Optionnel, par défaut le parent immédiat + ]) ->add('city', TextType::class) ->add('province', TextType::class) diff --git a/public/js/widgets/address-autocomplete.js b/public/js/widgets/address-autocomplete.js index 0eb117a..925fedc 100644 --- a/public/js/widgets/address-autocomplete.js +++ b/public/js/widgets/address-autocomplete.js @@ -9,6 +9,7 @@ class AddressAutocomplete extends HTMLElement { this.row = null; this.autocompleteChoices = null; this.api = ''; + this.parent = null; this.getPredictionsRoute = Routing.generate('eckinox_address_ajax_get_address_predictions', {}); this.getDetailsRoute = Routing.generate('eckinox_address_ajax_get_address_details', {}); } @@ -17,7 +18,8 @@ class AddressAutocomplete extends HTMLElement { { this.input = this.querySelector('input'); this.wrapper = this; - this.row = this.parentNode.parentNode; + this.parent = this.dataset.parent ?? null; + this.row = this.parent ? document.querySelector(this.parent) : this.parentNode.parentNode; this.autocompleteChoices = this.querySelector('.autocomplete-choices'); this.api = this.dataset.api; @@ -97,23 +99,39 @@ class AddressAutocomplete extends HTMLElement { this.row.addEventListener('populate-address', (event) => { const addressInput = this.input; let cityInput = this.row.querySelector('*[data-field-name="city"] input'); - let provinceInput = this.row.querySelector('*[data-field-name="province"] input'); - let countryInput = this.row.querySelector('*[data-field-name="country"] input'); + let provinceInput = this.row.querySelector('*[data-field-name="province"] input, *[data-field-name="province"] select'); + let countryInput = this.row.querySelector('*[data-field-name="country"] input, *[data-field-name="country"] select'); let postalCodeInput = this.row.querySelector('*[data-field-name="postalCode"] input'); // in the case where the form would be displayed in a modal if (cityInput == null || provinceInput == null || postalCodeInput == null) { cityInput = this.row.querySelector('*.city input'); - provinceInput = this.row.querySelector('*.province input'); - countryInput = this.row.querySelector('*.country input'); + provinceInput = this.row.querySelector('*.province input, *.province select'); + countryInput = this.row.querySelector('*.country input, *.country select'); postalCodeInput = this.row.querySelector('*.postal-code input'); } addressInput.value = event.detail.address; - cityInput.value = event.detail.city; - provinceInput.value = event.detail.province; - countryInput.value = event.detail.country; - postalCodeInput.value = event.detail.postalCode; + if (cityInput !== null) { + cityInput.value = event.detail.city; + } + if (provinceInput !== null) { + if (provinceInput.tagName === 'SELECT') { + this.selectOptionByTextOrValue(provinceInput, event.detail.province); + } else { + provinceInput.value = event.detail.province; + } + } + if (countryInput !== null) { + if (countryInput.tagName === 'SELECT') { + this.selectOptionByTextOrValue(countryInput, event.detail.country); + } else { + countryInput.value = event.detail.country; + } + } + if (postalCodeInput !== null) { + postalCodeInput.value = event.detail.postalCode; + } }); window.addEventListener('click', () => { @@ -121,6 +139,16 @@ class AddressAutocomplete extends HTMLElement { }); } + selectOptionByTextOrValue(selectElement, textOrValue) { + for (let option of selectElement.options) { + if (option.text === textOrValue || option.value === textOrValue) { + selectElement.value = option.value; + break; + } + } + selectElement.dispatchEvent(new Event('change')); + } + generateChoices(choices) { for (const choice of choices) { diff --git a/src/Api/GooglePlaces/Model/Address.php b/src/Api/GooglePlaces/Model/Address.php index fdf6776..54c9735 100644 --- a/src/Api/GooglePlaces/Model/Address.php +++ b/src/Api/GooglePlaces/Model/Address.php @@ -13,11 +13,19 @@ public static function fromPlacesResult(array $result): Address { $address = new Address(); - $address->address = $result["street_number"]->long_name." ".$result["route"]->short_name; - $address->city = $result["locality"]->long_name; - $address->province = $result["administrative_area_level_1"]->long_name; - $address->postalCode = $result["postal_code"]->long_name; - $address->country = $result["country"]->long_name; + $streetNumberAndRoute = []; + if (isset($result["street_number"])) { + $streetNumberAndRoute[] = $result["street_number"]->long_name; + } + if (isset($result["route"])) { + $streetNumberAndRoute[] = $result["route"]->short_name; + } + + $address->address = implode(' ', $streetNumberAndRoute); + $address->city = $result["locality"]->long_name ?? ''; + $address->province = $result["administrative_area_level_1"]->long_name ?? ''; + $address->postalCode = $result["postal_code"]->long_name ?? ''; + $address->country = $result["country"]->long_name ?? ''; return $address; } diff --git a/src/Form/Type/AddressAutocompleteType.php b/src/Form/Type/AddressAutocompleteType.php index e5c3273..9d5e374 100644 --- a/src/Form/Type/AddressAutocompleteType.php +++ b/src/Form/Type/AddressAutocompleteType.php @@ -15,6 +15,7 @@ public function configureOptions(OptionsResolver $resolver): void { $resolver->setDefaults([ 'api' => AddressCompleteApi::API_NAME, + 'parent' => null, ]); } @@ -22,6 +23,7 @@ public function buildView(FormView $view, FormInterface $form, array $options): { $view->vars['attr']['data-widget'] = 'address-complete'; $view->vars['api'] = $options['api']; + $view->vars['parent'] = $options['parent'] ?? null; parent::buildView($view, $form, $options); } diff --git a/templates/form/address_autocomplete.html.twig b/templates/form/address_autocomplete.html.twig index f5d2fd7..6bdea66 100644 --- a/templates/form/address_autocomplete.html.twig +++ b/templates/form/address_autocomplete.html.twig @@ -1,5 +1,5 @@ {%- block eckinox_address_autocomplete_widget -%} - +
From 2200c001f39304e39bd39e283fd81e1c9981bdda Mon Sep 17 00:00:00 2001 From: Jocelyn Menard Date: Fri, 12 Apr 2024 11:28:23 -0400 Subject: [PATCH 2/2] fix: Fixed zIndex error when using on collection type form --- public/js/widgets/address-autocomplete.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/js/widgets/address-autocomplete.js b/public/js/widgets/address-autocomplete.js index 925fedc..bb16741 100644 --- a/public/js/widgets/address-autocomplete.js +++ b/public/js/widgets/address-autocomplete.js @@ -205,7 +205,7 @@ class AddressAutocomplete extends HTMLElement { document.head.insertAdjacentHTML("afterbegin", `