I want to store my geopoints to firestore database but it wont work.
I created an array called acctPosition to store there the geopoints inside,
but in firebase i can't see the data, it looks like that nothing is stored.
How can I store the geopoints correctly?
The output:
The Geoloaction component:
data () {
coords: {
latitude: null,
longitude: null
},
acctPosition: []
},
...
mounted () {
var self = this;
// Try HTML5 geolocation.
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(function(position) {
var pos = {
lat: position.coords.latitude,
lng: position.coords.longitude
};
console.log(pos)
var acctPos = self.acctPosition.push(pos)
console.log(acctPos)
}
} else {
// Browser doesn't support Geolocation
}
let docId = `${this.currentUser.uid}`
// store geoData to currentUser in firebase firestore
fb.usersCollection.doc(docId).set({
acctPosition: this.acctPos
}).then(ref => {
console.log('work')
}).catch(err => {
console.log(err)
})
}
Javascript is asynchronous, so fb.usersCollection.doc(docId).set() is going to be executed before getCurrentPosition is finished.
You can push to firebase after getCurrentPosition is done:
mounted () {
...
var self = this;
// Try HTML5 geolocation.
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(function(position) {
var pos = {
lat: position.coords.latitude,
lng: position.coords.longitude
};
console.log(pos)
map.setCenter(pos);
var acctPos = self.acctPosition.push(pos)
console.log(acctPos)
let docId = `${self.currentUser.uid}`
// store geoData to currentUser in firebase firestore
fb.usersCollection.doc(docId).set({
acctPosition: self.acctPosition
}).then(ref => {
console.log('work')
}).catch(err => {
console.log(err)
})
}
} else {
// Browser doesn't support Geolocation
}
}
Related
I've made a custom hook, which can be used to fetch users location and find nearest marker on map based on that information.
Right now it works, but first object it returns is useStates default value. Response looks like this:
{
coordinates: { lat: '', lng: '' },
loaded: false
}
After returning object first time, it starts to work like it should:
{
coordinates: { lat: 45.024335, lng: 19.277089 },
loaded: true
}
So basically I don't want that the hook sends empty objects, with no values. How can I fix this?
const useGeoLocation = (markers) => {
const [location, setLocation] = useState({
loaded: false,
coordinates: { lat: "", lng: "" },
});
const onSuccess = (location) => {
// User location succesfully fetched, converting data format.
const targetPoint = turf.point([
location.coords.latitude,
location.coords.longitude,
]);
// Fetching data from markers parameter and converting data format.
var arr = [];
markers.map((marker) => arr.push(turf.point(marker.location)));
var points2 = turf.featureCollection(arr);
// Calculating which marker is nearest to targetPoint.
var nearest = turf.nearestPoint(targetPoint, points2);
// Setting location of nearest marker to usestate.
setLocation({
loaded: true,
coordinates: {
lat: nearest.geometry.coordinates[0],
lng: nearest.geometry.coordinates[1],
},
});
};
const onError = () => {
setLocation({
loaded: true,
coordinates: {
lat: 65.024335,
lng: 27.277089,
},
});
};
useEffect(() => {
if (markers) {
if (!("geolocation" in navigator)) {
onError();
}
navigator.geolocation.getCurrentPosition(onSuccess, onError);
}
}, [markers]);
return location;
};
Instead of just returning the location object as a whole, you could split the return into an object with values for the data, a loading state, an error message if needs be. For example:
const useGeoLocation = (markers) => {
const [location, setLocation] = useState(undefined);
const [error, setError] = useState("");
const onSuccess = (location) => {
// Rest of the success handler...
setLocation({
coordinates: {
lat: nearest.geometry.coordinates[0],
lng: nearest.geometry.coordinates[1],
},
});
};
const onError = () => {
setLocation({
coordinates: {
lat: 65.024335,
lng: 27.277089,
},
});
setError("Some error message");
};
useEffect(() => {
if (markers) {
if (!("geolocation" in navigator)) {
onError();
}
navigator.geolocation.getCurrentPosition(onSuccess, onError);
}
}, [markers]);
return {
data: location,
isLoading: !location && !error,
error: error,
};
};
Then when calling the hook you can do:
const {data, isLoading, error} = useGeoLocation();
and check for the value of data, or that isLoading and error are false, before doing anything.
There is lot of documentation about the hooks, but I don't seem to understand them well enough.
Code
const App = () => {
const [markers, setMarkers] = useState(null);
const fetchMarkers = async () => {
const res = await axios.get(`${process.env.REACT_APP_BASE_URL}/markers`);
setMarkers(res.data);
};
useEffect(() => {
fetchMarkers();
}, []);
useInterval(() => {
fetchMarkers();
}, 10000);
}
I've made a custom hook which returns an object, I can call it like this:
const location = useGeoLocation();
I would like to add markers as parameter to useGeoLocation hook. This can be achieved easily just by calling the function on code and adding markers.
Objective
My goal is to make sure that markers contains some value before calling useGeoLocation. Right now, geoLocation hooks parameter returns value of null, because application didn't have time to fetchMarkers and update the state.
I've tried
My first thought was to do something like this:
if (markers) {
const location = useGeoLocation(markers);
}
But of course, like stated in rules of hooks, hooks can't be used conditionally.
UPDATED 10.1.2022 - useGeoLocation hook
Here I'm fetching users location. On success, I will compare users location to an array of markers & find the closest one to user.
On error, I will return only a predefined location.
This doesn't work because onSuccess is executed before there is any data in markers(null). I'm not sure how to use if - else statement here, because I'm also using useEffect & useState.
Can someone help?
const useGeoLocation = (markers) => {
const [location, setLocation] = useState({
loaded: false,
coordinates: { lat: "", lng: "" },
});
const onSuccess = (location) => {
// User location succesfully fetched, converting data format.
const targetPoint = turf.point([
location.coords.latitude,
location.coords.longitude,
]);
// Fetching data from markers parameter and converting data format.
var arr = [];
markers.map((marker) => arr.push(turf.point(marker.location)));
var points2 = turf.featureCollection(arr);
// Calculating which marker is nearest to targetPoint.
var nearest = turf.nearestPoint(targetPoint, points2);
// Setting location of nearest marker to usestate.
setLocation({
loaded: true,
coordinates: {
lat: nearest.geometry.coordinates[0],
lng: nearest.geometry.coordinates[1],
},
});
};
const onError = () => {
setLocation({
loaded: true,
coordinates: {
lat: 65.024335,
lng: 27.277089,
},
});
};
useEffect(() => {
if (!("geolocation" in navigator)) {
onError();
}
navigator.geolocation.getCurrentPosition(onSuccess, onError);
}, []);
return location;
};
Add markers in the dependency array of useEffect hook of useGeoLocation and call navigator.geolocation.getCurrentPosition(onSuccess, onError) if the markers are available and in the else part you can call setLocation().
const useGeoLocation = (markers) => {
const [location, setLocation] = useState({
loaded: false,
coordinates: { lat: "", lng: "" },
});
useEffect(() => {
if (markers) {
if (!("geolocation" in navigator)) {
onError();
}
navigator.geolocation.getCurrentPosition(onSuccess, onError);
} else {
setLocation();
}
}, [markers]);
return location;
};
I'm receiving the following error in my componentDidMount function of my React component, and am unsure why:
Uncaught TypeError: this.setState is not a function
I've tried binding the geocode call but that doesn't seem to help. This also occurs when I call local functions that contain setState.
I've bound the componentDidMount function in the constructor.
Anybody know why this is occuring?
componentDidMount() {
if (this.state.initialLoad) {
navigator.geolocation.getCurrentPosition(
(position) => {
const pos = {
lat: position.coords.latitude,
lng: position.coords.longitude,
};
let geocoder = new google.maps.Geocoder();
let latlng = pos;
geocoder.geocode({
'latLng': latlng
},
function (results, status) {
if (status === google.maps.GeocoderStatus.OK) {
console.log(results);
if (results[1]) {
let addressObject = results[1].address_components;
const cityType = 'locality';
const stateType = 'administrative_area_level_1';
let city = "";
let state = "";
for (let i = 0; i < addressObject.length; i++) {
console.log(addressObject[i]);
if (addressObject[i].types.includes(cityType)) {
city = addressObject[i].long_name;
} else if (addressObject[i].types.includes(stateType)) {
state = addressObject[i].short_name;
}
}
let isCityStateFound = city != "" && state != "";
if (isCityStateFound) {
jQuery('#city-search-ready-status').val('true');
}
let query = isCityStateFound ? city + ', ' + state : EmptyStr;
console.log(query);
jQuery('.tab-panel').find('.input-text input').val(query);
this.setState({
searchValueCity: city,
searchValueState: state
});
this.performProviderSearch();
this.performLocationSearch();
} else {
console.log('No results found');
}
} else {
console.log('Geocoder failed due to: ' + status);
}
});
});
}
}
Welcome to the Stack Overflow Community!!!
You can easily solve all the problems by using ES6 features.
Arrow Functions - They have a lexical scoping. So you don't have to bind this anymore. This resource compare nicely the differences of functions before & after ES6.
ES6 Class - By combine the power of arrow functions now you can create methods without bind this in the class constructor.
class App extends Component {
state = {
name: "",
};
componentDidMount() {
if (this.state.initialLoad) {
navigator.geolocation.getCurrentPosition((position) => {
const pos = {
lat: position.coords.latitude,
lng: position.coords.longitude,
};
let geocoder = new google.maps.Geocoder();
let latlng = pos;
geocoder.geocode(
{
latLng: latlng,
},
(results, status) => {
// Convert this also to an Arrow Function
if (status === google.maps.GeocoderStatus.OK) {
console.log(results);
if (results[1]) {
let addressObject = results[1].address_components;
const cityType = "locality";
const stateType = "administrative_area_level_1";
let city = "";
let state = "";
for (let i = 0; i < addressObject.length; i++) {
console.log(addressObject[i]);
if (addressObject[i].types.includes(cityType)) {
city = addressObject[i].long_name;
} else if (addressObject[i].types.includes(stateType)) {
state = addressObject[i].short_name;
}
}
let isCityStateFound = city != "" && state != "";
if (isCityStateFound) {
jQuery("#city-search-ready-status").val("true");
}
let query = isCityStateFound ? city + ", " + state : EmptyStr;
console.log(query);
jQuery(".tab-panel").find(".input-text input").val(query);
this.setState({
searchValueCity: city,
searchValueState: state,
});
this.performProviderSearch();
this.performLocationSearch();
} else {
console.log("No results found");
}
} else {
console.log("Geocoder failed due to: " + status);
}
}
);
});
}
}
performProviderSearch = () => {
// Do whatever you want here
this.setState({
// Update the state
});
};
performLocationSearch = () => {
// Do whatever you want here
this.setState({
// Update the state
});
};
render() {
return (
<div className="App">
{/* Your HTML Structure */}
</div>
);
}
}
Note - Don't manipulate the DOM using jQuery or even using JavaScript. If you do then you're not using the full power of React.
Let me know if you need further support.
Try moving callback of geocoder.geocode to a separate function in component, bind it in constructor, and pass it as a callback.
P.S. Binding of componentDidMount is not needed.
I'm fairly new to React and I have run into a problem. I need to gather data from an API and then use the data to create Polygons with Google Maps. However, I'm experiencing problems accessing it.
When I log this.state.coordinates:
Console.log result of this.state.coordinates
However, when I try to log this.state.coordinates[0] it shows undefined. My guess is that the order in which the data binds is wrong, but I can't seem to find the solution. Here is my code:
constructor(props) {
super(props);
this.state = {
coordinates: [{}],
loading: 'initial'
};
}
componentDidMount() {
this.setState({
loading: 'true'
})
this.getData()
}
getData = async () => {
let coordinates = []
let res = await axios.get('https://smartcity-parking-api.herokuapp.com/sectors')
const sectors = await res.data.data
sectors.map(async (sector, i) => {
let res = await axios.get(sector.self_links.detail)
const coordinateArray = await res.data.data.coordinates
coordinates[i] = {
latlng: [],
id: res.data.data.sector_data.sector_id
}
coordinateArray.map(coordinate => {
let latlng = {
lat: coordinate.latitude,
lng: coordinate.longitude
}
coordinates[i].latlng.push(latlng)
})
coordinates[i].latlng.push({
lat: coordinateArray[0].latitude,
lng: coordinateArray[0].longitude
})
})
this.setState({
coordinates: coordinates,
loading: 'false'
})
}
render() {
let { coordinates, loading } = this.state
if (loading === 'initial') {
return <h2>Intializing...</h2>;
}
if (loading === 'true') {
return <h2>Loading...</h2>;
}
if (loading === 'false') {
return (
//Google maps here
);
}
I have tried making a loader, but it doesn't seem to be working. Any help would be very appreciated!
Why not set coordinates to null initially in your constructor and then have your conditional be
(loading === 'false' && coordinates)
That may solve your issue.
Change getData function to this.
getData = async () => {
let coordinates = []
let res = await axios.get('https://smartcity-parking-api.herokuapp.com/sectors')
const sectors = res.data.data
const sectorsLinks = await Promise.all(sectors.map(sector => axios.get(sector.self_links.detail)))
sectorsLinks.map((sector, i) => {
const coordinateArray = sector.data.data.coordinates;
coordinates[i] = {
latlng: [],
id: sector.data.data.sector_data.sector_id
}
coordinateArray.map(coordinate => {
let latlng = {
lat: coordinate.latitude,
lng: coordinate.longitude
}
coordinates[i].latlng.push(latlng)
})
coordinates[i].latlng.push({
lat: coordinateArray[0].latitude,
lng: coordinateArray[0].longitude
})
});
console.log(coordinates);
this.setState({
coordinates: coordinates,
loading: 'false'
})
};
Hi guys I need help in how to watch position in google maps with Ionic 3, I would like that upload position in real time in the firebase
In my home.ts I have the following code :
getMyPosition() {
this.geolocation.getCurrentPosition().then((result) => {
this.positionTruck = new google.maps.LatLng(result.coords.latitude, result.coords.longitude);
const mapOptions = {
zoom: 18,
center: this.positionTruck,
disableDefaultUI: true
}
this.map = new google.maps.Map(document.getElementById('map'), mapOptions);
this.truckMarker(this.positionTruck);
let watch = this.geolocation.watchPosition();
watch.subscribe((data) => {
let truck = { latitude: data.coords.latitude, longitude: data.coords.longitude };
this.truckService.updateGeolocation(this.truck.key, truck);
console.log(data.coords)
});
}).catch((error) => {
console.log('Erro ao tentar pegar sua localização ', error);
})
}
And now I have this code in service to update truck.service:
update(key: string, truck: any) {
return new Promise((resolve, reject) => {
this.db.list(this.PATH)
.update(key, (truck))
.then(() => resolve())
.catch((e) => reject())
})
}
this way when I test on the device, the home page giving refresh in page, why ?
Is this form correctly the update position ? help please.
import : import { Geolocation, Geoposition } from '#ionic-native/geolocation';
and declare :
public lat: number = 0;
public lng: number = 0;
and add in your code
let options = {
frequency: 3000,
enableHighAccuracy: true
};
this.watch = this.geolocation.watchPosition(options).filter((p: any) => p.code === undefined).subscribe((position: Geoposition) => {
console.log(position.coords.latitude + ' ++++++++++ ' + position.coords.longitude);
// Run update inside of Angular's zone
this.zone.run(() => {
this.lat = position.coords.latitude;
this.lng = position.coords.longitude;
);
});
});