I need to remove the partial postcode (in the red box) from the suggestions dropdown on autocomplete, so that users can only select a full postcode.
How do I achieve this or does anyone have a better suggestion?
I think everything works as it should but my client thinks to be able to select a partial postcode is too confusing.
This is my code:
let autocomplete;
let address1Field;
let postalField;
function initAutocomplete() {
address1Field = document.querySelector("#ship-address");
postalField = document.querySelector("#postcode");
autocomplete = new google.maps.places.Autocomplete(address1Field, {
componentRestrictions: {
country: ["gb"]
},
fields: ["address_components", "geometry"],
});
address1Field.focus();
autocomplete.addListener("place_changed", fillInAddress);
}
function fillInAddress() {
// Get the place details from the autocomplete object.
const place = autocomplete.getPlace();
let address1 = "";
let postcode = "";
for (const component of place.address_components) {
const componentType = component.types[0];
switch (componentType) {
case "street_number":
{
address1 = `${component.long_name} ${address1}`;
break;
}
case "route":
{
address1 += component.short_name;
break;
}
case "sublocality_level_1":
{
address1 += component.long_name;
break;
}
case "postal_code":
{
postcode = `${component.long_name}${postcode}`;
break;
}
case "postal_code_suffix":
{
postcode = `${postcode}-${component.long_name}`;
break;
}
case "postal_town":
document.querySelector("#postal_town").value = component.long_name;
break;
case "locality":
// document.querySelector("#locality").value = component.long_name;
break;
case "administrative_area_level_1":
{
// document.querySelector("#state").value = component.short_name;
break;
}
case "administrative_area_level_2":
document.querySelector("#county").value = component.long_name;
break;
}
}
address1Field.value = address1;
postalField.value = postcode;
document.getElementById('details').innerHTML = '<input name="latitude" type="hidden" id="latitude" value="' + place.geometry.location.lat() + '"><input name="longitude" type="hidden" id="longitude" value="' + place.geometry.location.lng() + '">';
}
window.initAutocomplete = initAutocomplete;
There is no easy way to do this, because those partial postal codes kind of are postal codes; they are postal code prefixes which is kind of a postal code in the Places API.
You can file a feature request for Place Autocomplete to support excluding certain types. Such a feature would allow you to request predictions including types=postal_code and excluding types=postal_code_prefix.
Currently, requesting predictions with types=postal_code will include predictions with types: ["postal_code_prefix", "postal_code"].
Without such a feature, the closest to the desired effect could be building your own widget, retrieve predictions using the Place Autocomplete Service and discarding those predictions withtypes: ["postal_code_prefix", "postal_code"]. There are 2 significant problems with this approach:
Probably not compliant with clause 3.2.3.(j) of the Google Maps Platform Terms of Service: (j) No Modifying Search Results Integrity. Customer will not modify any of the Google Maps Core Services’ search results.. You would need to seek legal advice about this.
The resulting user experience would be that typing rg1 produces only one prediction (RG1 8EQ), or possible no predictions at all.
All the above might be too much hassle considering that as soon as a blank space is added to the input (e.g. "rg1 ") most of the predictions will be for full precision postal codes, and as soon as an additional character is added (e.g. "rg1 1") all the predictions will be for full precision postal codes.
This is the intended behavior, users are expected to disambiguate short inputs like rg1 by adding a character, a blank space can often make a big difference.
Related
I am working with googles api places for address autocomplete suggestions.
This is my simple working code:
<!DOCTYPE html>
<html>
<body>
<form>
<input id="customerAddress" name="customerAddress" required autocomplete="off" />
<input id="zip" name="zip" required readonly />
<input id="city" name="city" required readonly />
</form>
<script
src="https://maps.googleapis.com/maps/api/js?key=MY_API_KEY&callback=initAutocomplete&libraries=places"
async
></script>
<script>
let autocomplete;
function initAutocomplete() {
autocomplete = new google.maps.places.Autocomplete(document.querySelector("#customerAddress"), {
componentRestrictions: { country: ["de", "DE"] },
fields: ["address_components", "geometry"],
types: ["address"],
});
autocomplete.addListener("place_changed", fillInAddress);
}
function fillInAddress() {
const place = autocomplete.getPlace();
var address = ""
var streetNumber = ""
for (const component of place.address_components) {
const componentType = component.types[0];
switch (componentType) {
case "route": {
address = component.long_name;
break;
}
case "street_number": {
streetNumber = component.long_name
break;
}
case "postal_code": {
document.querySelector("#zip").value = component.long_name;
break;
}
case "locality":
document.querySelector("#city").value = component.long_name;
break;
}
}
document.querySelector("#customerAddress").value = address +" "+streetNumber
}
</script>
</body>
</html>
Now I would realize the following situation:
the customer should write his address into the field "customerAddress" to get the suggestions, but the address have to include a street number. how can I restrict this?
The form should only be able to be submitted, if the customer selected a suggestions from the autocomplete list. If he / she write manually a address, which doesn't is from the autocomplete list, it has to be an error
Well, I think the best solution would be to have separate hidden input where you would put selected address which you would run validation against, if it is not defined you simply return error.
As for having street number you can also run the validation of selected Place. If it has selected type street_number it is valid, if not it's not.
I am not sure if you can disable Google to restricts search results to only addresses with street number.
I am working with activities and the fields, to, from, etc.
We have created custom views dynamically in order to make the selection easier. That is fine
My problem is... when you push the icon to search contacts... Is it possible add and order a custom list for the previewed 10 records?
To avoid the user clicking on the "Look up More records", select the custom view and add the "TO" record?
Custom views always gives the power for users to switch & select the records. If you cannot solve it by user training, then implement some form save (or pre-update plugin) validations to iterate through the party list & alert them when things are not in place.
Otherwise - I used to do this addPreSearch and addCustomFilter technique all the time. Read more
function FilterPartyList() {
var Regarding = Xrm.Page.getAttribute("regardingobjectid").getValue();
//checking if regarding fields is empty before we apply the filter
if (Regarding != null) {
Xrm.Page.getControl("requiredattendees").addPreSearch(Filter);
}
}
function Filter() {
var RegardingValue = Xrm.Page.getAttribute("regardingobjectid").getValue();
//if Regarding has a value, proceed
if (RegardingValue != null) {
//used to retrieve Name of the Account held in the Regarding field
var RegardingTextValue = RegardingValue[0].name;
//GUID used in filter
var RegardingID = RegardingValue[0].id;
var plist_filter = "<filter type='and'>" + "<condition attribute='parentcustomerid' operator='eq' name='" + RegardingTextValue + "' value='" + RegardingID + "' />" + "</filter>";
Xrm.Page.getControl("optionalattendees").addCustomFilter(plist_filter, "contact");
}
}
I am trying to load google autocomplete on two places in my page. One in the nav bar for searching the site and the second for the user to create an event by entering the address. I can get either one or the other working. And once I got both working but then it wouldn't fill in the info. I'd love to know what I am doing wrong, I have been banging my head against this for a hours now.
My inputs are
<input class="form-control" id="autocomplete" type="text" placeholder="Search..." name="term">
and
<input id="autocomplete2" placeholder="Enter address to store" type="text" autocomplete="off"></input>
and my js file
var placeSearch, autocomplete;
var componentForm = {
street_number: 'short_name',
route: 'long_name',
locality: 'long_name',
administrative_area_level_1: 'short_name',
country: 'long_name',
postal_code: 'short_name'
};
function initAutocomplete() {
autocomplete = new google.maps.places.Autocomplete(
(document.getElementById('autocomplete')), {
types: ['geocode']
});
autocomplete.addListener('place_changed', addlatlong);
autocomplete2 = new google.maps.places.Autocomplete(
document.getElementById('autocomplete2'), {
types: [ 'geocode' ]
});
autocomplete.addListener('place_changed', fillInAddress);
}
function addlatlong() {
var place = autocomplete.getPlace();
var latitude = place.geometry.location.lat();
var longitude = place.geometry.location.lng();
document.getElementById("latitude").value = latitude;
document.getElementById("longitude").value = longitude;
}
function fillInAddress() {
// Get the place details from the autocomplete object.
var place = autocomplete.getPlace();
for (var component in componentForm) {
document.getElementById(component).value = '';
document.getElementById(component).disabled = false;
}
var latitude = place.geometry.location.lat();
var longitude = place.geometry.location.lng();
document.getElementById("latbox").value = latitude;
document.getElementById("lngbox").value = longitude;
console.log(`${latitude}`)
console.log(`${longitude}`)
// Get each component of the address from the place details
// and fill the corresponding field on the form.
for (var i = 0; i < place.address_components.length; i++) {
var addressType = place.address_components[i].types[0];
if (componentForm[addressType]) {
var val = place.address_components[i][componentForm[addressType]];
document.getElementById(addressType).value = val;
}
}
}
Well first off, let's make sure those inputs are identical other than their ID's.
Here's a .slim example from an old project of mine:
form style="width:300px;margin: 0 auto;" action="/instructions" method="POST"
strong
p.input-label I'm currently at...
input style="width:300px;" id="autocomplete" placeholder="Enter your current address" onFocus="geolocate()" type="text" name="current_address" required="required"
strong
p.input-label And I need to get to...
input style="width:300px;" id="autocomplete2" placeholder="Enter your destination address" onFocus="geolocate()" type="text" name="destination_address" required="required"
input.button style="width:300px;" type="submit" value="What's the plan?"
Your inputs that you shared have different fields, some missing from the other, etc. Your first step should be making them identical in every way possible, and then slowly shifting one of them to your desired state.
I see you're using an older version of javascript, too. If possible you may want to consider refactoring to es5+
At the top you declare placeSearch and autocomplete, but not autocomplete2. This is another example of what I was suggesting earlier, about stepping through your code and ensuring that both inputs are being treated/created the exact same.
I see initAutocomplete is declared but never run. Is this intentional? Does the google module automatically call that function?
It seems to me like addlatlong() and fillInAddress() are the two functions you intend to use, one for autocomplete and the other for autocomplete2, but you reference autocomplete in both of them.
All in all, I think you've been messing with the code so much to try and make it work that you've lost sight of how it should be written in the end.
Perhaps starting a new file, fresh, and taking it one small step at a time might be the best way to figure out how to solve this.
Get one input working fully, as expected, and then add the next one in, step-by-step, the same way you implemented the first.
Good luck!
I want to implement a search box same as this, at first, just first dropdown list is active once user selects an option from the first dropbox, the second dropdown box will be activated and its list will be populated.
<s:select id="country" name="country" label="Country" list="%{country} onchange="findCities(this.value)"/>
<s:select id="city" name="city" label="Location" list=""/>
Jquery chained plugin will serve your purpose,
https://plugins.jquery.com/chained/
usage link - http://www.appelsiini.net/projects/chained
this plugin will chain your textboxes.
Try this code where based on your needs you have to populate it with your options:
var x;
$('#pu-country').on('change', function () {
if (this.value != '0') {
$('#pu-city').prop('disabled', false);
$('#pu-city').find("option").not(":first").remove();
$('#pu-location').prop('disabled', true);
$('#pu-location').val("Choose");
switch (this.value) {
case 'A':
x = '<option value="A.1">A.1</option><option value="A.2">A.2</option><option value="A.3">A.3</option>'
}
$('#pu-city').append(x)
} else {
$('#pu-location').prop('disabled', true);
$('#pu-location').val("Choose");
$('#pu-city').prop('disabled', true);
$('#pu-city').val("Choose");
}
});
$('#pu-city').on('change', function () {
if (this.value != '0') {
$('#pu-location').prop('disabled', false);
$('#pu-location').find("option").not(":first").remove();
switch (this.value) {
case 'A.1':
x = '<option value="A.1.1">A.1.1</option><option value="A.1.2">A.1.2</option><option value="A.1.3">A.1.3</option>'
break;
case 'A.2':
x = '<option value="A.2.1">A.2.1</option><option value="A.2.2">A.2.2</option><option value="A.2.3">A.2.3</option>'
break;
case 'A.3':
x = '<option value="A.3.1">A.3.1</option><option value="A.3.2">A.3.2</option><option value="A.3.3">A.3.3</option>'
break;
}
$('#pu-location').append(x)
} else {
$('#pu-location').prop('disabled', true);
$('#pu-location').val("Choose");
}
});
I have also set up and a demo to see the functionallity with more options.
FIDDLE
Your code should be something like this:
$(country).change(function(){
var l=Document.getElementByID("country");
for(i=0;i<=l.length;i++)
{
if(l.options[i].selected?)
{
text_array=[HERE YOU NEED TO ADD THE CITIES OF l.options[i].text];
val_array=[HERE YOU NEED TO ADD THE VALUES OF THECITIES OF l.options[i].text];
}
}
var c=Document.getElementByID("city");
c.options.text=[];
c.options.value=[];
//You now should have an empty select.
c.options.text=text_array ;
c.options.value=val_array ;
});
As I don't know, what kind of DB you use, to have the cities connected to their countrys, I can't tell you, what to put into the uppercase text...
Ciao j888, in this fiddle i tried to reconstruct the same system as the site you provided the link
the number of states cityes and locality is less but the concept remains the same
If you want to add a new state you must enter a new html options in select#paese with an id.
Then you have add in obj.citta a property with this id name and an array of cityes for a value.
The same thing for obj.localita where you will create an array of arrays.
The jQuery code you need is
<script type="text/javascript">
$(document).ready(function(){
var obj={
citta:{ //value is the same of option id
albania:['Durres','Tirana'],
austria:['Vienna','innsbruck','Graz'],
},
localita:{//for every city create a sub array of places
albania:[['località Durres1','località Durres 2'],['località Tirana','località Tirana 2']],
austria:[['località Vienna','località Vienna 2'],['località innsbruck','località innsbruck 2'],['località Graz','località Graz 2','località Graz 3']],
}
}
$('#paese').on('change',function(){
$('#località').attr('disabled','disabled').find('option').remove()
var quale=$(this).find('option:selected').attr('id')
var arr=obj.citta[quale]
if(arr){
$('#citta').removeAttr('disabled')
$('#citta option.added').remove()
for(i=0;i<arr.length;i++){
$('<option class="added">'+arr[i]+'</option>').appendTo('#citta')
}
}
})
$('#citta').on('change',function(){
var ind=($(this).find('option:selected').index())-1
var quale=$('#paese').find('option:selected').attr('id')
var arr=obj.localita[quale][ind]
if(arr){
$('#località').removeAttr('disabled')
$('#località option.added').remove()
for(i=0;i<arr.length;i++){
$('<option class="added">'+arr[i]+'</option>').appendTo('#località')
}
}
})
})
</script>
If this solution does not suit your needs, i apologize for making you lose time.
Hi i have done this for license and its dependent subject in yii 1.
The license dropdown
//php code
foreach($subject as $v) {
$subj .= $v['licenseId'] . ":" . $v['subjectId'] . ":" . $v['displayName'] . ";";
}
Yii::app()->clientScript->registerScript('variables', 'var subj = "' . $subj . '";', CClientScript::POS_HEAD);
?>
//javascript code
jQuery(document).ready(function($) {
//subject. dependent dropdown list based on licnse
var ty, subjs = subj.split(';'), subjSel = []; //subj register this varible from php it is
for(var i=0; i<subjs.length -1; i++) { //-1 caters for the last ";"
ty = subjs[i].split(":");
subjSel[i] = {licId:ty[0], subjId:ty[1], subjName:ty[2]};
}
//dropdown license
jQuery('#license#').change(function() {
$('#add').html(''); //clear the radios if any
val = $('input[name="license"]:checked').val();
var selectVals = "";
selectVals += '<select>';
for(var i=0; i<subjSel.length; i++) {
if(subjSel[i].licId == val) {
if(subjSel[i].subjId *1 == 9) continue;
selectVals += '<option value="'+subjSel[i].subjId+'">'+subjSel[i].subjName+'</option>';
}
}
selectVals += '</select>';
$("#subject").html(selectVals);
});
});
You seem to be asking two questions:
QUESTION 1. How to have a disabled select box (the second and third select boxes in the case of your example) which is activated upon the selection of an option from the first select box.
ANSWER 1:
simply use the disabled=true/false as below...
<select id="country" name="country" label="Country" onchange="document.getElementById('city').disabled=false; findCities(this.value)"/>
<select id="city" name="city" label="Location" disabled=true/>
NOTE: I changed "s:select" to "select" on the basis that your question does not make reference or tag the Struts framework that uses this syntax.
QUESTION 2: How to populate the second select box when a selection is made in the first.
ANSWER 2: There are many ways to do this, and the choice depends on where you have the data to populate the lists with. In the case of your Rentalcars example, if you chose Barbados, the browser sends an ajax GET request to "http://www.rentalcars.com/AjaxDroplists.do;jsessionid=5DCBF81333A88F37BC7AE15D21E10C41.node012a?country=Barbados&wrapNonAirports=true" -try clicking on this link and you will see what that request is sending back. This '.do' address is a server side file of a type used with the Struts framework I mentioned above.
A more conventional approach, which would be included in your function findCities(country)would be to send an AJAX request to a PHP script which queries a database and sends back an array of place names to the browser. The AJAX javascript code includes instructions as to what to do with the response. Without knowing more about where you want to store your list, giving an example of this would most likely not be useful.
Alternatively, the whole list of places could be included in the javascript script as an array (as demonstarated by Devima, above), in a text document on the server as comma separated values, or you could save it to a browser database like WebSQL or IndexedDB if offline use would be useful.
When you have got your list, probably as an array of values, you could save the array as a variable eg. var cities=result (in the case of a simple ajax request). You will then need to iterate through cities, for example
for (var i = 0; i < cities.length; i++){
var place=cities[i];//an individual city name
document.getElementById("city").innerHTML+="<option value='" + place + "'>" + place + "</option>";//adds an 'option' with the value being the city name and the text you see being the city name
}
IMO this is the base case AngularJS was designed to completely alleviate. Check it out!
I am new to JavaScript and I have been doing some work creating a form in HTML and JavaScript. In this work I have been trying to limit the string of a field depending on the text entered into a previous field.
What i have been trying is if the country 'Australia' is entered into the 'Country' text box than the 'Postcode' text box is limited to only 4 numbers (the Australian postcode standard)
i have done this much of a function so far:
document.getElementById('txtcountry').onblur = function postcode()
{
var country = document.getElementById('txtcountry').value;
if (country == "Australia" || category == "australia")
{
document.getElementById('txtpostcode').maxLength = 4;
}
else
{
document.getElementById('txtpostcode').maxLength = 9;
}
}
Here is the segment of the initial HTML that i have to use the function with:
<b>Postcode:</b> <input type="text" id="txtpostcode" name="postcode">
<br>
<b>Country:</b> <input type="text" id="txtcountry" name="country">
I am calling the function using :
<form name="rego" action="submit.htm" onsubmit="return !!(validateText() & validateCheckBoxes(this) & validateRadioButton() & validateEmail() & populateInstitution() & postcode());" method="POST">
Any help would really be appreciated!
UPDATE: i have updated my function to the finished function after some help as it doesn't seem to work and i need some further help with it
Are you trying to set the maxLength property:
var pc = document.getElementById('txtpostcode');
pc.maxLength = 4;
pc.value = pc.value.substr(0,4); // remove any extra characters already entered
...and then add an else condition to set the maxLength to whatever your default is for other countries.
You would then call your postcode() function from the blur event of your txtcountry field.
EDIT: Note that the function you've shown has an undefined variable category in the second part of the if test - should be country. And as I mentioned already you do need to call the function from somewhere.
I would use the
var country = document.getElementById('txtcountry');
if (country.value == "Australia" || category == "australia")
{
country.setAttribute("maxlength","4");
country.value = country.value.substr(0,4);
}