I'm working on a bit of user management code. Basically, on click of a button, I want it to save a new user, and then display an incoming password I'm saving in the Store. My code looks a little like this:
onClick() {
/*Insert filling up the newUser variable from the form here*/
this.store.dispatch(new AddUser(this.newUser))
this.store.select(userFeature.getPassword).subscribe(
pass => {
this.temp = pass; //I've tried using this.password here, but also nothing
})
setTimeout(() => {
this.pause();
}, 5000);
//this.password = "Stuff" <-- This DOES work
this.password = temp //This executes despite the wait above
}
pause(){
if(this.temp === null){
setTimeout(() => {
this.pause();
}, 500);
console.log("Waiting...")
}
}
In my HTML I'm using the {{password}} in a simple span.
EDIT: Fixed! I needed to use a ChangeDetectorRef.
this.store.dispatch(new AddUser(this.newUser))
this.store.select(userFeature.getPassword).subscribe(
pass => {
this.password = pass;
this.cd.detectChanges();
});
There are multiple things done wrong in your code snippet, the first thing to clarify is synchronous and asynchronous execution.
A block of code is typically executed from top to bottom line after line, this is what we would call "synchronous execution" example :
// Start of block
let variable = 1; // Here variable is going to have a value of 1
variable = variable + 1; // Here variable is going to have a value of 2
// End of block
Now let's look at an asynchronous execution, and the best way to illustrate it in an example is using setTimout, but keep in mind that there are many asynchronous operations like calling a backend endpoint, or using Promise / Observable
// Start of block 1
let variable = 1; // Here variable is going to have a value of 1
setTimeout(() => {
// Start of block 2
variable = variable + 1; // Here variable is going to have a value of 3
variable = variable + 1; // Here variable is going to have a value of 4
// End of block 2
}, 1000);
variable = variable + 1; // Here variable is going to have a value of 2
// End of block 1
So in this example execution of "Block 1" is synchronous and execution of "Block 2" is synchronous, but Block 2 gets executed at a later time (in this example 1 second later). It does not mean that Block 1 is going to wait 1 second then execute Block 2 and continue executing Block 1. It's called non-blocking, each Block is going to execute uninterrupted, and they may or may not execute at the same time, in many cases, there is no way of really controlling that.
NgRx
Now that we explained non-blocking and asynchronous let's talk about NgRx.
// Start of block
store.dispatch(...)
store.select(...)
// End of block
Dispatch and Select are going to get executed one after the other and each one has some asynchronous code that it's going to trigger. This means that you can't guarantee that the asynchronous code of Dispatch is going to get executed before the asynchronous code of Select, which result in your password being undefined because you are reading it before it's being set, now eventually it's going to get set but not synchronously.
In your example, you can quickly fix it by just wrapping your logic around a check if the password is set like this
this.store.select(userFeature.getPassword).subscribe(
pass => {
if(pass) {
this.temp = pass;
/* Do Something with your pass */
}
}
)
// OR
this.store.select(userFeature.getPassword).pipe(
filter((pass) => !!pass),
tap((pass) => {
this.temp = pass;
/* Do Something with your pass */
}),
).subscribe()
In other cases it can be more complicated than that as you'd need to use some synchronization token in your Action and State to make sure you are reading the value corresponding to the right action side effect.
You should not use this.cd.detectChanges();
for this
NOTE
I just addressed the snippet, but I don't see what is the functional requirement for something like your example you might want to rethink your logic. Also, don't forget to unsubscribe from your select, this is important.