geolocation.watchPosition() not working in Ionic 4 - location

I am learner in Ionic and present in my application I am trying to get user location using below code but it's not working properly.
I mean lat and longs are coming but very slowly location lat and longs changing when user move one place to another. Is there any better solution for getting user current location?
this.geolocation.getCurrentPosition().then((resp) => {
}).catch((error) => {
console.log('Error getting location', error);
});
let watch = this.geolocation.watchPosition();
watch.subscribe((data) => {
this.data = data;
console.log("----->Watch latitude" + data.coords.latitude);
console.log("-----> Watch logitude" + data.coords.longitude)
console.log("-----> Watch accuracy" + data.coords.accuracy)
});

You can increase the accuracy by passing the enableHighAccuracy option:
this.geolocation.getCurrentPosition({ enableHighAccuracy: true })
or
this.geolocation.watchPosition({ enableHighAccuracy : true, timeout: 10000 })
You can also pass params for increasing the frequency the call is made such as timeout, this is explained in the README:
"enableHighAccuracy: Provides a hint that the application needs the best possible results. By default, the device attempts to retrieve a Position using network-based methods. Setting this property to true tells the framework to use more accurate methods, such as satellite positioning. (Boolean)
timeout: The maximum length of time (milliseconds) that is allowed to pass from the call to navigator.geolocation.getCurrentPosition or geolocation.watchPosition until the corresponding geolocationSuccess callback executes. If the geolocationSuccess callback is not invoked within this time, the geolocationError callback is passed a PositionError.TIMEOUT error code. (Note that when used in conjunction with geolocation.watchPosition, the geolocationError callback could be called on an interval every timeout milliseconds!) (Number)
maximumAge: Accept a cached position whose age is no greater than the specified time in milliseconds. (Number)"
https://github.com/apache/cordova-plugin-geolocation

Related

Cypress: global variables in callbacks

I am trying to set up a new Cypress framework and I hit a point where I need help.
The scenario I am trying to work out: a page that is calling the same endpoint after every change and I use an interceptor to wait for the call. As we all know you can’t use the same intercept name for the same request multiple times so I did a trick here. I used a dynamically named alias, which works.
var counters = {}
function registerIntercept(method, url, name) {
counters[name] = 1;
cy.intercept(method, url, (req) => {
var currentCounter = counters[name]++;
cy.wrap(counters).as(counters)
req.alias = name + (currentCounter);
})
}
function waitForCall(call) {
waitForCall_(call + (counters[call.substr(1)]));
// HERE counters[any_previously_added_key] is always 1, even though the counters entry in registerIntercept is bigger
// I suspect counters here is not using the same counters value as registerIntercept
}
function waitForCall_(call) {
cy.wait(call)
cy.wait(100)
}
It is supposed to be used by using waitForCall(“#callalias”) and it will be converted to #callalias1, callalias2 and so on.
The problem is that the global counters is working in registerIntercept but I can’t get its values from waitForCall. It will always retrieve value 1 for a specific key, while the counters key in registerIntercept is already at a bigger number.
This code works if you use it as waitForCall_(“#callalias4”) to wait for the 4th request for example. Each intercept will get an alias ending with an incremented number. But I want to not keep track of how many calls were made and let the code retrieve that from counters and build the wait.
Any idea why counters in waitForCall is not having the same values for its keys as it has in registerIntercept?

How to execute 2 async calls in redux-observable epic and return/dispatch action on result of each one

I have an action which requires me to go to the server, get 2 chunks of data, and on getting those then dispatching an action with each chunk of data respectively.
This is to be done when action$.ofType(PROCESSDATA).
Pretty new to rxjs and I can't quite figure out the right combination.
epic = (action$) => {
return action$.ofType(PROCESSDATA)
//should I be using switchMap? It is for initialising data
//so I figure no point in carrying on with original request
//if a new one comes in
.switchMap(action=>{
//is merge right? return statement currently just gives me
//an error about my epic does not return a stream
const token = localStorage.getItem('token');
return Observable.merge(
Observable.ajax({
url:'/first',
headers:{Authorization:'Bearer ' + token}
})
.map(r=>{type:PROCESSFIRST, data:r.response, item:action.item}),
Observable.ajax({
url:'/second',
headers:{Authorization:'Bearer ' + token}
})
.map(r=>{type:PROCESSSECOND, data:r.response}),
)
})
}
The reason I am doing it this way (in case it doesn't make sense) is that I already have an app using redux-thunk (and axios) and I am trying to replace one part of it with redux-observable to get the hang of it, so that is why I want to issue the 2 actions (PROCESSFIRST and PROCESSSECOND) for redux-thunk to deal with as they are already catered for. So I am simply putting a step in the middle to see if I can work with redux-observable but I am very much a newbie to rxjs etc
Ultimately I want to trigger the continuation actions using the data returned and then finish at that.
Also, if you have time, how and where should errors be handled in this.
UPDATE:
OK, so I just realised I need a return statement at the top of the epic. That gets me out of the first error.
Then I was using mapTo instead of map, and I was using r.data where it should have r.response. Amazingly it all works now. BUT I am not handling errors correctly OR not calling it in the right way.
So, because of what I said about the existing project using redux-thunk, I have an actionCreator that controls this:
initState = (lang) => {
return dispatch => new Promise(resolve,reject){
const pr1 = dispatch({type:INIT_STATE});
//this was another thunk that returned a Promise which did the axios
//calls to the server, dispatched the relevant continuation action
//and then either resolved or rejected
//and then dispatched further actions to process the results
const pr2 = dispatch(processData());
Promise.all([pr1,pr2])
.then(r=>resolve(true))
.catch(e=>reject(e))
}
}
I have changed this where const pr2 = .... to:
const pr2 = dispatch({type:PROCESSDATA})
, thereby swapping the thunk for an epic and left everything else the same. This does seem to trigger the epic and process the data but for example if I use the wrong url, nothing happens (as expected) but more importantly I don't catch the error. So what do I need to change to catch that error?
thanks in advance

RxJS - Queueing ajax requests from separate inputs

I have a list of multiple inputs (dynamically generated - unknown number).
I want each to trigger an ajax request on every keystroke
I want these ajax requests to be queued up, so only one is sent to
the server at a time, and the next one is sent only after getting a response from the earlier one.
if new requests are triggered from an input that already has requests in the queue, I want the old ones associated with the same input to be cancelled.
if new requests are triggered from an input that does not already have inputs in the queue, I want the new requests to just be added to the end of the queue without cancelling anything.
I'm told that RxJS makes these kinds of complicated async operations easy, but I can't seem to wrap my head around all the RxJS operators.
I have queueing working with a single input below, but I don't really understand why the defer is necessary or how to queue requests for separate inputs while maintaining the switchMap-like behavior I think I want for individual inputs themselves.
Rx.Observable.fromEvent(
$("#input"),
'keyup'
)
.map((event) => {
return $("#input").val();
});
.concatMap((inputVal) => {
return Rx.Observable.defer(() => Rx.Observable.fromPromise(
fetch(myURL + inputVal)
))
.catch(() => Rx.Observable.empty());
})
.subscribe();
First of all you have to create some sort of function that manages each input. Something along the following lines
requestAtKeyStroke(inputId: string) {
return Rx.Observable.fromEvent(
$(inputId),
'keyup'
)
.map((event) => {
return $("#input").val();
})
.filter(value => value.length > 0)
.switchMap((inputVal) => Rx.Observable.fromPromise(fetch(myURL + inputVal)))
}
Such a function deals with your third requisite, to cancel requests still on fly when a new one arrives. The key here is the switchMap operator.
Then what you can do is to merge all the Observables corresponding to your inputs into one Observable. One way could be the following
Observable.from(['input1, 'input2']).map(input => requestAtKeyStroke(input)).mergeAll()
This is not fulfilling all you requisites, since you still may have more than one requests under execution at the same time, coming from different inputs. I am not sure though if it is possible to fulfill all your requisites at the same time.

Is it problematic to request the server on every character typed in?

In my frontend I have an input-field that sends an ajax request on every character typed in (using vue.js) to get realtime-filtering (can't use vue filter because of pagination).
Everything works smooth in my test environment, but could this lead to performance issues on (a bigger amount of) real data and if so, what can I do to prevent this?
Is it problematic?
Yes.
The client will send a lot of requests. Depending on the network connection and browser, this could lead to a perceptible feeling of lag by the client.
The server will receive a lot of requests, potentially leading to degraded performance for all clients, and extra usage of resources on the server side.
Responses to requests have a higher chance of arriving out of order. If you send requests very fast, it has increased chances of being apparent (e.g. displaying autocomplete for "ab" when the user has already typed "abc")
Overall, it's bad practice mostly because it's not necessary to do that many requests.
How to fix it?
As J. B. mentioned in his answer, debouncing is the way to go.
The debounce function (copied below) ensures that a certain function doesn't get called more than once every X milliseconds. Concretely, it allows you to send a request as soon as the user hasn't typed anything for, say, 200ms.
Here's a complete example (try typing text very fast in the input):
function debounce(func, wait, immediate) {
var timeout;
return function() {
var context = this, args = arguments;
var later = function() {
timeout = null;
if (!immediate) func.apply(context, args);
};
var callNow = immediate && !timeout;
clearTimeout(timeout);
timeout = setTimeout(later, wait);
if (callNow) func.apply(context, args);
};
}
var sendAjaxRequest = function(inputText) {
// do your ajax request here
console.log("sent via ajax: " + inputText);
};
var sendAjaxRequestDebounced = debounce(sendAjaxRequest, 200, false); // 200ms
var el = document.getElementById("my-input");
el.onkeyup = function(evt) {
// user pressed a key
console.log("typed: " + this.value)
sendAjaxRequestDebounced(this.value);
}
<input type="text" id="my-input">
For more details on how the debounce function works, see this question
I actually discuss this exact scenario in my Vue.js training course. In short, you may want to wait until a user clicks a button or something of that nature to trigger sending the request. Another approach to consider is to use the lazy modifier, which will delay the event until the change event is fired.
It's hard to know the correct approach without knowing more about the goals of the app. Still, the options listed above are two options to consider.
I hope this helps.
The mechanism I was searching for is called debouncing.
I used this approach in the application.

Cancel ajax calls?

I'm using the Select2 select boxes in my Django project. The ajax calls it makes can be fairly time-consuming if you've only entered a character or two in the query box, but go quicker if you've entered several characters. So what I'm seeing is you'll start typing a query, and it will make 4 or 5 ajax calls, but the final one returns and the results display. It looks fine on the screen, but meanwhile, the server is still churning away on the earlier queries. I've increased the "delay" parameter to 500 ms, but it's still a bit of a problem.
Is there a way to have the AJAX handler on the server detect that this is a new request from the same client as one that is currently processing, and tell the older one to exit immediately? It appears from reading other answers here that merely calling .abort() on the client side doesn't stop the query running on the server side.
If they are DB queries that are taking up time, then basically nothing will stop them besides stopping the database server, which is of course not tangible. If it is computation in nested loops for example, then you could use cache to detect whether another request has been submitted from the same user. Basically:
from django.core.cache import cache
def view(request):
start_time = timestamp # timezone.now() etc.
cache.set(request.session.session_key + 'some_identifier', start_time)
for q in werty:
# Very expensive computation with millions of loops
if start_time != cache.get(request.session.session_key + 'some_identifier'):
break
else:
# Continue the nasty computations
else:
cache.delete(request.session.session_key + 'some_identifier')
But the Django part aside - what I would do: in JS add a condition that when the search word is less than 3 chars, then it waits 0.5s (or less, whatever you like) before searching. And if another char is added then search right away.
I.e.
var timeout;
function srch(param) {
timeout = false;
if (param.length < 3) {
timeout = true;
setTimeout(function () {
if (timeout) {
$.ajax({blah: blah});
}
}, 500);
} else {
$.ajax({blah: blah});
}
}

Resources