I use VueCLI and i do have such code inside methods:
submitCheck: function () {
function authUser() {
// returns a promise
}
function uploadFile() {
// also returns a promise
}
// ...
if ( error !== null ) {
EventBus.$emit('showError', error)
} else {
authUser()
.then(
function () {
return uploadFile();
})
.then(
function (data) {
EventBus.$emit('loaderStop')
this.$router.push('/awaiting');
})
.catch(function(error) {
EventBus.$emit('loaderStop')
console.log(error)
})
}
What i want to achieve is to route to /awaiting if all promises are resolved, but since i use this inside an anonymous function it doesnt have router. I am sure many coders met such a problem and needed to route from inside a function. How to do it?
Kalreg.
Multiple ways to handle this, I'd suggest you use arrow functions and learn about their differences to the other function style.
to be clear:
replace
function (data) {
EventBus.$emit('loaderStop')
this.$router.push('/awaiting');
}
with
data => {
EventBus.$emit('loaderStop');
this.$router.push('/awaiting');
}
You question context is not clear enough. If the code is executed in exponent methods, you can use arrow funciton like (agrs,...) => {...}. Otherwise, if this is not the case, you can use bind function like (function() {}).bind(this). Or just import $router in your code module.
Hope this can help you.
The answers from Sandro and Xhua are perfect. I just want to explain, WHY you get the error:
The problem is "this.". It refers to the parent object. So in your case "this." refers to the authUser Object and not to Vue. For your understanding: You could define "var that = this" outside of your authUser object and then use "that." inside. Or you go for the more sophisticated solutions.
Related
I am currently working on a project where I want to deference an array of functions (function references) and excecute the function.
This does only work, if I don't call another class method within the function.
Otherwise I get "Uncaught TypeError" and I can't figure out how to solve this error.
Here's my code sample 'working' the same way my original project does:
After calling function2 the engine cannot find this.log...
Do you have ideas? Thank you very much in advance.
KR, Robert
class ArrayWithFunctions {
constructor() {
this.functionTable = [
this.function1,
this.function2,
];
}
execute(index) {
return (this.functionTable[index])();
}
log(chars) {
console.log(chars);
}
function1() {
console.log('I am Function 1.');
}
function2() {
this.log('I am Function 2.');
}
}
let example = new ArrayWithFunctions();
example.execute(0);
example.execute(1);
This is an example of Javascript's execution contexts in action. In this situation, to avoid losing the correct reference to the class, you can bind the functions when putting them inside the array, or initialize them as arrow functions:
Example 1: Bind them in the constructor:
constructor() {
this.functionTable = [
this.function1.bind(this),
this.function2.bind(this),
];
}
Example 2: Create them as arrow functions:
class ArrayWithFunctions {
// ...
function1 = () => {
console.log('I am Function 1.');
}
function2 = () => {
this.log('I am Function 2.');
}
}
You can use arrow functions to dodge scoping issues:
function2 = () => {
this.log('I am function 2.');
}
Related: How to access the correct `this` inside a callback (and you might also want to take a look at How does the "this" keyword work?).
In this case you can simply set the correct this value by calling the function with .call:
return this.functionTable[index].call(this);
Does anyone know if is it syntactically possible to apply the parameter properties as local scope methods for the parent function to reference.
The module is very large which increase page load times and shouldn't be imported via import() at top level.
import {method1, method2, method3} from "./module.js" //not an option
//Working example.
$('some-id').on('click', () => {
import ("./module.js")
.then( (module) => {
module.method();
module.method2();
module.method3();
// module methods...
});
}
//Something along these lines.
$('some-id').on('click', () => {
import ("./module.js")
.then( ( module ) => {
method();
method2();
method3();
//Apply the module methods to function scope without direct reference to the parameter
//this would save some time and loads of repetition if possible, question is can anything similar be done.
});
}
This would be pretty similar!
$('some-id').on('click', async () => {
const { method, method2, method3 } = await import("./module.js");
method();
method2();
method3();
});
Within a React function element I have a use Effect hood that has some callback based stuff going on. At the end of the callback chain, I need to return a function to cleanup on dismounting. How is that done.
I have something like this:
ReactFunctionElement=(..)=>{
useEffect(()=>{
asyncCall()
.then(..)
.cath(..)
.finally(
return ()=>{cleanup stuff}
)
},[some filters])
}
But the cleanup stuff never gets run. I don't know how, or if it is even possible, to lift that back out into the useEffect and return.
I think you need something like this:
useEffect(() => {
// Closure variable
const thingToCleanup = null;
asyncCall()
.then(thingToCleanup = thingFromAsync...)
.catch(...);
return () => {
// cleanup stuff using thingToCleanup
});
} ,[some filters]) }
Your useEffect function has to return the clean up function, .finally returns a Promise which won't work but you also don't return that (JavaScript will implicitly return undefined). But you need access to some variables from the setup code in the cleanup so you store those in a closure to use later during clean up.
you can subscribe an api call and in cleanup function you can unsubscribe it. here is an example:
useEffect(() => {
api.subscribe(userId);
return () => api.unsubscribe(userId);
}, [ userId ])
Please see this minimum example:
I have data like this:
const testObject = { test: 'foo' };
And my main function is this:
Cause error
// This cause error
function handleResponse(response) {
return response.json().then(Promise.reject); // Please notice this line
}
try {
await handleResponse({
json: () => Promise.resolve(testObject),
});
} catch (err) {
console.log(err);
// => TypeError: PromiseReject called on non-object
}
And this one works:
Correct
// This works
function handleResponse(response) {
return response.json().then((res) => Promise.reject(res)); // Please notice this line
}
try {
await handleResponse({
json: () => Promise.resolve(testObject),
});
} catch (err) {
console.log(err);
// => {test: "foo"}
}
Why is this happening? What did I missing?
something.then(Promise.reject) gets a reference to the reject method and passes just that function reference. It no longer has any connection to the Promise object. This means that the this value when the reject() method is called will be incorrect and it does not allow that.
As Patrick mentioned in a comment, it's the same reason you can't do this:
let reject = Promise.reject;
reject("whatever");
Methods need to be called with the context of their object unless they are specifically designed to not need the context of their object (there are some instances of that).
If you want a shortcut, you could do this:
something.then(Promise.reject.bind(Promise))
That will bind the Promise object to the method (by essentially creating a stub function that calls it as Promise.reject()).
Other related answers:
Why does this throw an undefined exception?
When you pass 'this' as an argument
Object methods assigned to variables or function arguments fail when invoked
Assiging a method to a variable in Javascript
Uncaught TypeError: this.method is not a function - Node js class export
I'm trying to update the state from the promise which I received using the fetch function.
componentDidMount(){
fetch(url).then((responseText) => {
var response = responseText.json();
response.then(function(response){
this.setState(response);
});
});
}
I was getting the error that the setState is not an function
Then, I tried to bind(this) to pass the this value like below.
componentDidMount(){
fetch(url).then((responseText) => {
var response = responseText.json();
response.then(function(response){
this.setState(response);
});
}).bind(this);
}
It is not working now also. Same error again.
This is because of the scoping of this, so you're on to something when you're trying to use Function.prototype.bind. Your mistake is that you don't bind all the way down to the last anonymous function. What you probably want to do is use arrow functions all the way, like this:
componentDidMount(){
fetch(url)
.then((responseText) => responseText.json())
.then((response) => this.setState(response));
}
Arrow functions always keep the context of this.
Sorry, Just now found that I didn't bind the this variable properly.
Now, It is fixed.
componentDidMount(){
fetch(url).then((responseText) => {
const response = responseText.json();
response.then(function(response){
this.setState(response);
});
}.bind(this));
}
Your second promise doesn't have the current this context. You can use an arrow function here as well.
componentDidMount(){
fetch(url).then((responseText) => {
return responseText.json();
})
.then((response) => {
this.setState(response);
});
}
Also, chaining instead of nesting your promises will help with the legibility and might help you to avoid callback hell.
You also have the wrong method to setState it should look something like setState({name : 'string'})