I'm running into a problem, and not an expert of async/rxjs development.
Let me explain my problem:
I have an angular service TimeoutService
which only contains a processTimeout()
method:
processTimeout(timeout: NodeJS.Timeout, stillLoading: boolean): void {
if (timeout !== undefined) {
clearTimeout(timeout);
}
timeout = setTimeout(() => {
if (stillLoading) this.dialog.open(LoadingDialogComponent);
}, this.TIMEOUT_DURATION_MS);
}
processTimeout()
does the following:
Takes a NodeJS.Timeout
as parameter, and a stillLoading
boolean
.
first it checks if timeout is already on and clear it if so.
Then i set my timeout and if at the timeout callback the stillLoading
value is true
(which always is because when i pass it as parameter to the processTimeout
method from componentA
the value is true
), I open a dialog saying that request is taking to much time.
Problem is, the stillLoading
boolean passed to method is an attribute of my standard angular components (for example lets call it ComponentA
that has a boolean
loadingA
attribute ), and I already know that js/ts has pass-by-value for primitive types:
It is set to true when I call my api service and set to false when loading is completed (when subscribe to my api request has been done).
But setting the value of loadingA
to false occurs after I call the processTimeout()
method from my service.
processTimeout()
stays a reference or pointer (the same for me but I do not really know how Js/Ts works behind the scenes, but a variable should have an internal memory / DOM Hex address) or even observable or something so the value of stillLoading
in processTimeout()
stays the same as my attribute loadingA
of my componentA
? (Attribute loadingA
is passed as stillLoading
parameter and is also a primitive boolean
type in componentA
).Because of the nature of the timeout that makes the code inside it execute after the timeout, i need the boolean value at that time (from the componentA
), and not the value it was when passed-by-value in the method.
I'm down to listen to every possible solution, and if possible respecting ts and angular best practices.
Thanks.
Tried: not a lot to be honest because I prefer some advice before losing hours on this problem, had an idea to pass a newly instanciated observable pointing on my componentA
loadingA
attribute, but I'm not sure at all of my comprehension of the way observables works for this kind of cases.
Expecting: the stillLoading
method parameter in processTimeout
being the same variable (same memory address) than my componentA
loadingA
boolean attribute, or any workaround solution/clues on tools i can use to fullfill my need.
The code does not necessarily need to be on the service, you can create a common class that two children inherit, that contain this code. This will ensure that the function has access to the component variables, because each child will have its own scope!
export class Common {
processTimeout(timeout: NodeJS.Timeout, stillLoading: boolean): void {
if (timeout !== undefined) {
clearTimeout(timeout);
}
timeout = setTimeout(() => {
if (stillLoading) this.dialog.open(LoadingDialogComponent);
}, this.TIMEOUT_DURATION_MS);
}
}
child
export class ParentA extends Common {
loading: false;
constructor(private timeoutService: TimeoutService) {
super()
}
ngOnInit() {
this.timeoutService(5000, this.loading);
this.loading = true;
}
}
This can be done with any number of children!
As you said you can pass by reference and ensure the service has the latest value!
In your component, you can call it like
export class ParentA {
loadingWrapper = {
loading: false,
}
constructor(private timeoutService: TimeoutService) {}
ngOnInit() {
this.timeoutService(5000, this.loadingWrapper);
this.loadingWrapper.loading = true;
}
}
in your service you can change it to
processTimeout(timeout: NodeJS.Timeout, stillLoadingWrapper: {loading: boolean}): void {
if (timeout !== undefined) {
clearTimeout(timeout);
}
timeout = setTimeout(() => {
if (stillLoadingWrapper.loading) this.dialog.open(LoadingDialogComponent);
}, this.TIMEOUT_DURATION_MS);
}