Prevent Google Distance Matrix Service from using AREA codes - reactjs

I am working on a core piece of my form functionality that finds the distance between two ZIP codes. It does find the distance accurately, but unfortunately, this Google Distance Matrix API is also searching for existing area codes, which can result in random and unnecessary mileage returns.
Currently, I can find the mileage between 64154 and 816 (19.1), but I would like to completely omit the return of any AREA CODE data.
This is the function that returns said data:
handleChange = (e) => {
const name = e.target.name
const value = e.target.value
this.setState({
[name]: value
//call back function to make sure we get the last character from the user input
}, () => {
this.getMiles(this.state.origin, this.state.destination)
})
}
getMiles = (origin, destination) => {
const {google} = this.props
let service = new google.maps.DistanceMatrixService()
console.log(origin)
console.log(destination)
service.getDistanceMatrix({
origins: [origin],
destinations: [destination],
travelMode: 'DRIVING',
unitSystem: google.maps.UnitSystem.IMPERIAL,
avoidHighways: false,
avoidTolls: false
}, (response, status) => {
if (status !== 'OK') {
alert('Error was: ' + status);
} else {
let originList = response.originAddresses;
let destinationList = response.destinationAddresses;
if (response.rows[0].elements[0].status === 'NOT_FOUND'){
return false
} else{
this.setState({mileage: response.rows[0].elements[0].distance.text.replace("mi", " ")})
}
}
});
}
I can't find anything in the documentation that would allow me to filter out certain address types. I have even tried to put different form limitations regarding character length, which works for the most part, but the user can still put three digits in and "space" all the way to the end of the input. This will, unfortunately, bypass my conditional and return the data for the AREA CODE because the character length that I am looking for will be fulfilled "816 ".length === 5

Well, I just ended up using a regex pattern to check to see if the string contains 5 digits that are numbers.
What this does is, it doesn't prevent the API from returning AREA CODE searches but it does prevent my mileage from calculating by constantly setting it to zero:
let fiveNumberMatch = /^[0-9]{5}$/;
<h1>{!this.state.origin.match(fiveNumberMatch) || !this.state.destination.match(fiveNumberMatch) ? this.state.mileage = 0 : this.state.mileage}</h1>
Works for now!

Related

Velo by Wix, JSON data in repeater

I'm trying to get the temperature of each hour from this website: https://www.smhi.se/vader/prognoser/ortsprognoser/q/Stockholm/2673730
I'm getting the data from https://opendata-download-metfcst.smhi.se/api/category/pmp3g/version/2/geotype/point/lon/16/lat/58/data.json. The "t" object is the temperature.
The problem I have is displaying the data for each hour in the repeater.
Here is my backend-code:
import { getJSON } from 'wix-fetch';
export async function getWeather() {
try {
const response = await getJSON('https://opendata-download-metfcst.smhi.se/api/category/pmp3g/version/2/geotype/point/lon/16/lat/58/data.json');
console.log(response) // all data
const tempData = response.timeSeries[0].parameters[10].values[0];
return tempData // Only returns "t" - temperature
} catch (e) {
return e;
}
}
The backend part works, however the frontend doesn't.
import { getWeather } from 'backend/getSMHI.jsw'
$w.onReady(function () {
(
getWeather().then(weatherInfo => {
$w('#weatherRepeater').onItemReady(($item, itemData, index) => {
if (index > 6) {
$item('#tempText').text = itemData.timeSeries[index].parameters[1].values[0];
} else if (index === 6) {
$item('#tempText').text = itemData.timeSeries[index].parameters[0].values[0];
} else {
$item('#tempText').text = itemData.timeSeries[index].parameters[10].values[0];
} // The parameters number for "t" changes depending on the index
})
$w('#weatherRepeater').data = weatherInfo;
})
)
})
Seems like there are at least a couple of issues here.
First, you are retrieving a single number from the API and trying to put that in a repeater. From the description of what you're trying to do, it would seem that you mean to be retrieving a list of numbers, probably as an array. You probably want to do some filtering and/or mapping on the response data instead of directly accessing a single value.
Second, the data you send to a repeater must be in the proper format. Namely, it must be an array of objects, where each object has a unique _id property value (as a string). You are not doing that here. You are simply assigning it a number.
Third, and this is just an efficiency thing, you don't need to define the onItemReady inside the then(). Not that it will really make much of a difference here.

Angular/Firestore Collection Document Query to return a single document field from all documents into an array

I am performing a query on my collection documents and trying to return just all phone numbers into an array. I just want to set the phone numbers into array for use by another function. Firebase docs only show a console log for (doc.id) and (doc.data) and no practical use for any other objects in your documents. My console log for info.phoneNumbers returns all the phoneNumbers.
async getPhone() {
await this.afs.collection('members', ref => ref.where('phoneNumber', '>=', 0))
.get().toPromise()
.then(snapshot => {
if (snapshot.empty) {
console.log('No Matches');
return;
}
this.getInfo(snapshot.docs);
});
}
getInfo(data) {
data.forEach(doc => {
let info = doc.data();
console.log(info.phoneNumber, 'Phonenumbers');
// let myArray = [];
// myArray.push(doc.doc.data());
// const phoneNumber = info.phoneNumber as [];
// console.log(myArray, 'ARRAY');
return info.phoneNumber;
})
}```
Firestore is a "document store database". You fetch and store entire DOCUMENTS (think "JSON objects") at a time. One of the "anti-patterns" when using document store databases is thinking of them in SQL/relational DB terms. In SQL/relational DB, you "normalize" data. But in a document store database (a "NoSQL" database) we explicitly denormalize data -- that is, we duplicate data -- across documents on write operations. This way, when you fetch a document, it has all the data you need for its use cases. You typically want to avoid "JOINs" and limit the number of references/keys in your data model.
What you are showing in the code above is valid in terms of fetching documents, and extracting the phoneNumber field from each. However, use of .forEach() is likely not what you want. forEach() iterates over the given array and runs a function, but the return value of forEach() is undefined. So the return info.phoneNumber in your code is not actually doing anything.
You might instead use .map() where the return value of the map() function is a new array, containing one entry for each entry of the original array, and the value of that new array is the return value from map()'s callback parameter.
Also, mixing await and .then()/.catch() is usually not a good idea. It typically leads to unexpected outcomes. I try to use await and try/catch, and avoid .then()/.catch() as much as possible.
So I would go with something like:
try {
let querySnap = await this.afs.collection('members', ref =>
ref.where('phoneNumber', '>=', 0)).get();
let phoneNumbers = await this.getInfo(querySnap.docs[i].data());
} catch(ex) {
console.error(`EXCEPTION: ${ex.message}`);
}
getInfo(querySnapDocs) {
let arrayPhoneNumbers = querySnapDocs.map(docSnap => {
let info = doc.data();
let thePhoneNum = info.phoneNumber
console.log(`thePhoneNum is: ${thePhoneNum}`);
return thePhoneNum;
});
return arrayPhoneNumbers;
});
I solved this with help and I hope this may be helpful to others in Getting access to 1 particular field in your documents. In my service:
async getPhone() {
return await this.afs.collection('members', ref => ref.where('phoneNumber', '>=', 0))
.get().toPromise()
.then(snapshot => {
if (snapshot.empty) {
console.log('No Matches');
return;
}
return this.getInfoNum(snapshot.docs);
});
}
getInfoNum(data) {
return data.map(doc => {
let info = doc.data();
return info.phoneNumber
});
}
In my Component using typescript
phoneNumbers: string[] = [];
getPhone() {
this.dbService.getPhone().then(phoneNumbers => {
this.phoneNumbers = phoneNumbers;
this.smsGroupForm.controls.number.setValue(phoneNumbers.join(',')) //sets array seperated by commas
console.log(phoneNumbers);
});
}
This returns all the phone numbers in a comma separated array.
In my template I pull the numbers into an input for another function to send multiple text. Code in the template is not polished yet for the form, I am just getting it there for now.
<ion-list>
<ion-item *ngFor="let phoneNumber of phoneNumbers">
<ion-label position="floating">Phone Number</ion-label>
<ion-input inputmode="number"
placeholder="Phone Number"
formControlName="number"
type="number">{{ phoneNumber }}
</ion-input>
</ion-item>
</ion-list>

How do I get an axios.get call to stop, so that a new call has new data?

I am doing an axios.get call on an API, in React. When I run it the first time, I get the results that I expect. When I run it the next time and search for the same thing, I get more results than I had originally. Then if I search again, for the same thing, I get even more results that I had the second time. It keeps adding new results to the old ones without starting a brand new search. If I search for a different keyword, then I get results with both the new keyword results and the old ones that I did before.
There is probably an easy fix to this, but how do I get it to discard the old results and create new ones? I have tried creating CancelTokens, but haven't been successful.
I am currently putting the results into a new array and I set that array equal to nothing when I first render the component, so I don't understand how this problem is happening in the first place.
Thanks for any help you can offer!
async componentDidMount() {
//searches the api for the hashtag that the user entered
newArray.length=0;
newArray=[];
await axios.get(`https://laffy.herokuapp.com/search/${this.props.toSearch}`).then(function(response) {
returnedKeywordSearch = response.data;
}) //if the api call returns an error, ignore it
.catch(function(err) {
return null;
});
//goes through the list of locations sent from the api above and finds the latitude/longitude for each
var count = 0;
while (count < returnedKeywordSearch.length) {
locationToSearch = returnedKeywordSearch[count].location;
if (locationToSearch !== undefined) {
var locationList = await axios.get(`https://api.mapbox.com/geocoding/v5/mapbox.places/${locationToSearch}.json?access_token=pk.eyJ1IjoibGF1bmRyeXNuYWlsIiwiYSI6ImNrODlhem95aDAzNGkzZmw5Z2lhcjIxY2UifQ.Aw4J8uxMSY2h4K9qVJp4lg`)
.catch(function(err) {
return null;
});
if (locationList !== null) {
if (Array.isArray(locationList.data.features) && locationList.data.features.length)
{
locationCoordinates.push(locationList.data.features[0].center);
if (returnedKeywordSearch[count].location!== null && returnedKeywordSearch[count].location!==""
&& locationList.data.features[0].center !== undefined)
{newArray.push({
id: returnedKeywordSearch[count].id,
createdAt: returnedKeywordSearch[count].createdAt,
text: returnedKeywordSearch[count].text,
name: returnedKeywordSearch[count].name,
location: returnedKeywordSearch[count].location,
coordinates: locationList.data.features[0].center
});
}
}
}
}
count++;
}
//tweetSpots is set to null in the initial component state set up
this.setState({tweetSpots: newArray});
this.setState({ done: true}); //sets done to true so that loading animation goes away and map displays
}
Okay, I figured out this problem is actually on the server side in Express where the data isn't being reset. So, I'll close this one and open a question about Express.

map redux saga results

Code
I followed this stackoverflow post to understand how to use the map with the yield.
my code is splitted in 3 parts:
Example data
citiesCode = [
{
bankCityId: A305
cityId: B544
},
{
bankCityId: R394
cityId: D873
},
]
1) the function that invoke when i launch the relative action
export function* getInvoiceCities({ citiesCode }) {
yield call(invoiceCities, citiesCode);
}
2)this function allow me to map the array that citiesCode is
export function* invoiceCities(citiesCode) {
yield all(citiesCode.map(cityCode => call(getCityInfo, cityCode)));
}
3) in this last function i use the relative code to made a call to the bankCityUrl and cityUrl to obtain the information about the relative city.
const citiesInfoList = [];
function* getCityInfo({ bankCity, city }) {
const cityUrl = `/cities/${city}`;
const bankCityUrl = `/cities/${bankCity}`;
try {
const cityInfoResponse = yield call(fetchWrapper, {
url: cityUrl,
});
const bankCityInfoResponse = yield call(fetchWrapper, {
url: bankCityUrl,
});
citiesInfoList.push(cityInfoResponse, bankCityInfoResponse);
console.log('cities.info', citiesInfoList);
// if (cityInfoResponse.status && bankCityInfoResponse.status === 'success') {
// yield put(saveInvoiceCitiesResponse(citiesInfoList));
// }
} catch ({ packet, response }) {
if (response.status !== 422) {
yield put(pushError({ text: 'sendPraticeSectionError' }));
}
}
BUG
The main bug is: If I call multiple time getInvoiceCities save to make this redux call I store the same cities more and more time.
Just to make an example:
citiesInfoList = []
I call it for the first time: I console.log('cities.info', citiesInfoList); citiesInfoList will be filled with the right results
I call it for the second time: I console.log('cities.info', citiesInfoList); citiesInfoList will be filled with the right results x 2
I call it for the second time: I console.log('cities.info', citiesInfoList); citiesInfoList will be filled with the right results x 3
there is a way to avoid this behaviour ? can i stop to store multiple times the same results ?
This scenario is happening because all your sagas sits in one file
If I undertood you correctly, when you call an action that invokes getInvoiceCities, it will invoke invoiceCities, and the later will invoke getCityInfo for each cityCode.
BUT, since you have defined const citiesInfoList = []; in the same module. What happens next is that getCityInfo will start using citiesInfoList for each getCityInfo invocation, resulting in a duplicated results as you have described.
I suggest the following:
Recommended: Get citiesInfoList out of this file to a separate file, and build a reducer to manage it.
Reset citiesInfoList = [] before every push.
i found, just some hours ago, an easy answer.
1) i deleted citiesInfoList = [] ( it was very ugly to see imho)
2) in the second function i did this
export function* invoiceCities(citiesCode) {
const results = yield all(
citiesCode.map(cityCode => call(getCityInfo, cityCode)),
);
yield put(saveInvoiceCitiesResponse(results));
}

Changing date doesn't show new data in react native

I am working on a react native app where i'm using native base for design purpose. I am using date picker from native base. Also i'm showing different results of different dates which i'm fetching from api. Now, some dates have data and some don't. When I pick a date that doesn't have data it shows blank as expected. But after showing blank I can't get data from other dates which have data. it kind of gets stuck. But if I select the dates that have data,it works fine. Here's the code I have now:
async setDate(newDate) {
let day = newDate.getDate()
console.log('date', day)
let month = newDate.getMonth() + 1
let year = newDate.getFullYear()
day = String(day).length > 1 ? day : '0' + day
month = String(month).length > 1 ? month : '0' + month
let fullDate = 'https://myapi'+year+month+day
await fetch(fullDate, {
method: 'GET',
})
.then((response) => response.json())
.then((response) => {
console.log('new', response)
if(response === null){
this.setState({
tableData1: [],
tableData2: [],
tableData3: [],
})
} else {
const first = response.First
this.setState({ tableData1: first })
const second = response.Special
this.setState({ tableData2: second })
const third = response.Consolidation
this.setState({ tableData3: third })
}
})
}
What can I do to get data as usual after selecting a date which doesn't have any value?
I'm quite surprised you're not receiving any errors here in console or on screen - are you testing on a device or simulator?
if(response === null) is your problem, undefined === null evaluates to false, so you're pushing into your else statement and trying to access response.First etc which is undefined and will cause an error to throw - this is why things get 'stuck'.
You can simplify your check and, as mentioned in my comment, the if else could be cleaned up quite a bit as you don't need to assign data from the response object to variables because you're not re-using them - and your multiple calls to setState will cause three re-renders of the component.
Some examples of how concise this block could be. I'll explain what I'm doing as I'm unaware of your experience and other readers may be less experienced than yourself:
if(!response)
this.setState({tableData1: [], tableData2: [], tableData3: []})
else
this.setState({
tableData1: response.First,
tableData2: response.Special,
tableData3: response.Consolidation
})
A simple if(!response) check to fix the error, setState being merged into one call and values being pulled directly from the response object. You'll notice i've omitted the curly braces from both the if and else blocks as they are both single statement blocks.
Or you could take it one step further:
.then((response) => {
this.setState({
tableData1: response.First ? response.First : [],
tableData2: response.Special ? response.Special : [],
tableData3: response.Consolidation ? response.Consolidation : []
})
}
Here we combine into a single setState call, using a ternary operator to assign each piece of state to data from the response object, or to an empty array. You'll notice each condition is based on response.key instead of just response - this is safer and less likely to cause errors (unless you're absolutely certain there can be no situation in which response contains some, but not all, of those keys)

Resources