Unable to access "this" inside promise in Angular [duplicate] - javascript

This question already has answers here:
How to access the correct `this` inside a callback
(13 answers)
Closed 2 years ago.
The following function is used to find the country-code of the user and store it in the local Storage. However, I am unable to access this inside the promise and the console log returns "null".
successfulLookup(position) {
const { latitude, longitude } = position.coords;
fetch(`https://api.opencagedata.com/geocode/v1/json?q=${latitude}+${longitude}&key=d2c9d6477126472fbe51b721a2d34399`)
.then((response) => { return response.json() })
.then((jsonRes) => {
console.log(jsonRes.results[0].components.country_code);
console.log(this);
this.dataSharingService.universalLocalStorageSetter(jsonRes.results[0].components.country_code,"countryCode");
})
}
I am calling the function findCountry inside NgOnInit
findCountry() {
if (window.navigator.geolocation) {
window.navigator.geolocation
.getCurrentPosition(this.successfulLookup);
}
}
The following question has been asked a couple of times and the solution is to use Arrow function but I am already using an Arrow function. Any help is appreciated.
UPDATE
successfulLookup(position) {
const { latitude, longitude } = position.coords;
const self = this;
fetch(`https://api.opencagedata.com/geocode/v1/json?q=${latitude}+${longitude}&key=d2c9d6477126472fbe51b721a2d34399`)
.then((response) => { return response.json() })
.then((jsonRes) => {
console.log(jsonRes.results[0].components.country_code);
console.log(self);
self.dataSharingService.universalLocalStorageSetter(jsonRes.results[0].components.country_code,"countryCode");
})
}
tried defining const self=this

You need to change the code like
window.navigator.geolocation
.getCurrentPosition(this.successfulLookup.bind(this));
We need to use bind(this) to the successfulLookup method because that method is calling by the getCurrentPosition. In that case, this refers to the getCurrentPosition.
I posted the concept of a bind in my youtube videos. If you are interested you can check the link. I also posted an angular course that has about 100 videos covering all the concepts. Here is the link below.
Leela Web Dev

Related

not able to update the UI from setTimeout() in vuejs [duplicate]

This question already has answers here:
How to access the correct `this` inside a callback
(13 answers)
Closed 1 year ago.
i want to update name of person after every second in ui after feching name from lifeSpanObj object in .vue file (vuejs).
<div> {{personName}}</div> // in template using this this(its example not exactly this)
this.lifeSpanObj.forEach((element, i) => {
setTimeout(function () {
this.personName = element.name;
console.log(this.personName);
}, 1000);
});
using the above example i am able to print updated values in console but UI does not get updated. what could fix for this?
Make sure always use arrow function to not shadow this keyword:
this.lifeSpanObj.forEach((element, i) => {
setTimeout(() => { // arrow function instead of anonymous function
this.personName = element.name; // now this refers to the vue component
console.log(this.personName);
}, 1000);
});
for primitive function (in ES5) you can still follow the below approach
this.lifeSpanObj.forEach((element, i) => {
var self = this;
setTimeout(function () {
self.personName = element.name;
console.log(self.personName);
}, 1000);
});

Setting class data inside axios.get().then() has no effect on the data [duplicate]

This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Why is my variable unaltered after I modify it inside of a function? - Asynchronous code reference
(7 answers)
Closed 3 years ago.
I have the following ES6 code:
export default class HomePage extends Component {
constructor(props) {
super(props);
this.state = {
itemsWithData: []
};
this.details = [1, 2, 3] ;
}
loadDetails = items => {
items.forEach(item => {
axios
.get(item.url)
.then(response => {
this.details = response.data;
})
.catch(e => {
console.warn(`Error while getting ${item.name} details`);
});
});
console.log(this.details);//It prints [1,2,3]
};
}
As you can see, I'm setting this.details inside then.I've logged the this.detailsinside then just to make sure it sees the class context. It indeed does. But somehow, setting the details seems to have no effect at the function end. It prints the old value. The response returned from the request has absolutely different data each time. So it's never [1,2,3]. What should I do to get the details data changed appropriately? Is it something to do with async-await?
P.S. In fact, the content of the arrow function passed to then is this:
this.details[item.name]=response.data;
So, I'm not stupidly setting details to a new value at each turn.

Undefined 'this' in Promise + array. reduce() [duplicate]

This question already has answers here:
How to access the correct `this` inside a callback
(13 answers)
Closed 5 years ago.
I'm facing a problem since this morning.
WHAT I HAVE
Basically, I have a simple class, with an array of files to register:
function MyClass() {
this.filesToRegister = [
{
"fileName": "http://tny.im/azk"
},
{
"fileName": "http://tny.im/azk"
}
];
}
I have also a simple function, _contextFunction() which takes a single fileToRegister entry:
MyClass.prototype._contextFunction = function(fileToRegister) {
return new Promise((resolve, reject) => {
logger.info(typeof this.filesToRegister);
logger.info('current file: ' + fileToRegister);
return resolve();
});
};
Note that this function MUST access to the context (the this), it's mandatory, and I can't change that.
Finally, I have a utility method, processArray(), that can apply a function on each item of an array, all done synchronously:
MyClass.prototype.processArray = function(array, fn) {
let results = [];
return array.reduce((p, item) => {
return p.then(() => {
return fn(item).then((data) => {
results.push(data);
return results;
}).catch(err => console.log(err));
});
}, Promise.resolve());
};
WHAT I TRY TO DO
I use this utility method to apply _contextFunction() on each item of the filesToRegister array:
this.processArray(this.filesToRegister, this._contextFunction);
It works without problem and execute this._contextFunction() on each item of this.filesToRegister.
WHAT THE PROBLEM IS
BUT, when I try to log typeof this.filesToRegister in _contextFunction(), the result is undefined... After several tests, I concluded that nothing in the context is accessible (neither context attributes nor context methods).
However, if I execute this._contextFunction() without the processArray() method, I can access to the context (both context attributes and context methods).
WHAT I THINK
My guess is that the problem comes from the processArray() method, but I don't see where... I tried to log typeof this.filesToRegister right in the processArray() method, and it works...
To conclude:
processArray() IS able to access to the context.
this._contextFunction() launched 'standalone' IS able to access to the context.
this._contextFunction() launched by processArray() IS NOT able to access to the context.
Can anyone help me? Thanks
fn(item)
Calls the function without the context. Use:
fn.call(this, item)
Alternatively pass the method name:
this.processArray(this.filesToRegister,"_contextFunction");
And then do:
this[fn](item);
How i would do that:
class MyClass {
constructor(){
this.files = [];
}
async add(file){
await "whatever";
this.files.push(file);
}
multiple(name, array){
return Promise.all( array.map(el => this[name](el)));
}
}
And then:
const instance = new MyClass;
instance.add("whatever");
instance.multiple("add",[1,2,3]);

Angular 2 typescript Variable value changes withing scope [duplicate]

This question already has answers here:
How to return value from an asynchronous callback function? [duplicate]
(3 answers)
Closed 5 years ago.
I am using Angular 2 for creating a webapp and ran into a weird problem which is worth understanding.
I am trying to print the value of an object right after assigning a new value and a bit later. Following is the code:
do {
this._sharedService.readServerStatus().subscribe(res =>
{
this.surveyStatus = JSON.parse(JSON.stringify(res));
console.log(this.surveyStatus);
});
console.log("ne");
console.log(this.surveyStatus);
}
while(this.surveyStatus.isBusy());
In this code, surveyStatus is an object which I wish to print to the console. Following is the output from the browser console:
Object {serverBusy: 1, terminate: 0}
ServerStatus {}
The first one is printed out as expected, while when I read it outside the loop, something weird happens to the object.
Can someone help me understand what's going on.
The problem is that your readServerStatus() call is async and therefore will print the value when it's emitting a value. But the rest of your code doesn't wait for it, so your second console.log prints an empty object.
But there's a huge problem with your code, your generating tons of subscriptions inside your while loop without completing them, which will lead to a memory leak.
I would suggest to use the repeatWhile operator with takeUntil of RxJs for such a task.
Here's an example:
let mockResponse = { serverBusy: 1, terminate: 0 };
const request = () => {
return Rx.Observable.of(mockResponse).delay(500); // emulate api call
};
request()
// repeat the request while isBusy is true
.repeatWhen(notifications => {
return notifications.takeWhile(() => {
return !!mockResponse.serverBusy;
});
})
.subscribe(res => {
console.log(res);
});
setTimeout(() => {
mockResponse.serverBusy = 0;
}, 2000);
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/5.4.3/Rx.min.js"></script>
Here's another example using switchMap to read the data from the response and decide if you need to retry, if not emit the response.
let mockResponse = { serverBusy: 1, terminate: 0 };
const apiCall = () => {
return Rx.Observable.of(mockResponse).delay(500); // emulate api call
}
function makeRequest$() {
let request$ = apiCall()
.switchMap(res => {
console.log('is busy:', !!res.serverBusy);
return !!res.serverBusy ? request$ : Rx.Observable.of(res);
});
return request$;
}
makeRequest$().subscribe(res => {
console.log(res);
});
setTimeout(() => {
mockResponse.serverBusy = 0;
}, 2000);
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/5.4.3/Rx.min.js"></script>
it's happening because the console print outside the subscription will not wait for the new value assignment. It will be printed before new value arrives and assings this.surveyStatus = JSON.parse(JSON.stringify(res));. So while you are subscribing, if you wanted to do anything on value changes, put whole thing inside the subscription.

How to make this line of code work? [duplicate]

This question already has answers here:
How do I return the response from an Observable/http/async call in angular?
(10 answers)
Closed 5 years ago.
var relative = af.database.object('users/user75ECZOiNtxZwYoezaXmYA9YwPm53', { preserveSnapshot: true });
relative.subscribe(
snapshot => {
this.usedBasicProfile = snapshot;
}
);
console.log(this.usedBasicProfile); //the value is undefined, how to make this work?
what I want to do is get the data from the firebase, anyone could help me?
It appears you're using an async method which means the value is not available until execution gets inside the callback handler. Have you tried this?
var relative = af.database.object('users/user75ECZOiNtxZwYoezaXmYA9YwPm53', { preserveSnapshot: true });
relative.subscribe(snapshot => {
this.usedBasicProfile = snapshot;
console.log(this.usedBasicProfile);
});

Categories

Resources