Hi!
I have a data action in a web block that should only be fetched when a (boolean) input parameter has a certain value.
So I set the Fetch parameter of the data action to "Only at demand".
Now the question is, at which point can start the asychronous fetch?
If I put it in OnInitialize (after checking the input parameter), Service Studio complains: 'OnInitialize action' accesses Aggregates or Data Actions, but the data might not be available at this time, which sounds strange to me.
I could move the input parameter check into the Data action, but then I would have an unnecessary server request, in case the aggregate does not have to be fetched. I want to decide client side whether the data action should be executed.
This situation is applicable for a lot of situations, also with aggregates.
How to tackle this?
yes, exactly
so each thing you want to refresh separately needs a screen action doing the refresh
and then with timeout :
with promise :
you can see in the console logs at the right, that the refresh starts a bit quicker with the promise.
Dorine
Hello Rogier,
why don't you do this on the after fetch of other aggregates that are fetched at start. Or try to add this on the on ready. You should not have that problem if you use the on ready.
Also when and where is this variable changed? Maybe you call the data action there.
Let me know if this helps.
Best regards,
Lourenco Matalonga
Hi Lourenco,
Thanks for you response.
Your suggestion would not be the best for my situation, I would say.
First of all, if I move it to the OnReady event, the same warning appears. Besides that, I do not want to wait unit OnReady to start the fetch. The delay this causes is unnecessary and there is no relation with the DOM to be ready.
Second, move to an OnAfterFetch of a different data action is not applicable because there is no other data action or aggregate. Besides that, it is unecessary to wait for another data action to be fetched, because at OnInitialize, I already know that the data must be fetched, so why wait?
Rogier
Hmm but does it work on initialize despite the warning? Having a warning does not always mean that you are doing something wrong. It is just so you are aware of what you are doing. Because from my understanding you just require to fetch the data and you are not performing any action on the data on the on initialize. So this should be just fine! If it works i would disregard the warning.(You can hide it if it annoys you)
Yes, it does!
So I am wondering 2 things:
1. Why does this warning appear?
2. Will the fetching in OnOnitialize block the screen rendering? "Keep this event handler action simple and avoid slow actions, since it may delay the rendering of the Screen or Block" I am afraid so.
Good news!
Warning appears because OutSystems sets up patterns that check your code for bad practices. This one is an exception I would say. But in most cases this would should up to users trying to manipulate the data or doing something with the results of the data and that is not possible on the on initialize as the data might not available yet (bad practice).
Regarding the second point I am pretty sure the since you are fetching new data the screen will render again... Since the block and screen depend on this data. So it might slow a little bit the process but at same time I don't think it will be noticeable. Give it a try and see how it performs and if it has the expected behavior .
Hi Rogier,
I assume you know the value on the parent screen or block already because you are referring to a (boolean) input parameter.
Can you instead solve this by adding an IF statement on the parent screen or block
If the value matches. Load the block. if not, do nothing.
Kind regards,
Thomas Druif
Thanks for you answer Thomas,
Yes, the value is already known in the parent block, but if the value does not match, the block still has to be loaded and show some info. Only the data action doesn not have to be fetched. But still the block must show stuff.
To get an idea, in this situation, it is about a date picker. In some cases it shows an initial date that is provided by the parent block in an input parameter. But in some other cases it should fetch the initial date from an external web service.I do not want to bother the parent context with that.
Anyway, the exact situation here is not relevant. There are a lot of other cases I need to decide whether or not to fetch an aggregate or data action, depending on the block's input.
Why do you only want to fetch in certain cases ? Purely for avoiding unneccesary server calls ? I would say : don't solve a performance problem until it becomes a problem.
1) I think the simplest solution would be to just have it fetched at start and when the boolean changes also in the OnParametersChanged, and inside the server action, just decide to stop without actually doing anything if boolean doesn't have desired value. No need for OnAfterFetch, no need for local variables.
2) You could decide to be a bit smarter about it in the OnParametersChanged, only refreshing the data action if the boolean turns to true.
But then you are left with the messy business of all the ways your data action output is used in the block : you can't change the output values from client side, so either
3) One step further : you don't automatically fetch at start, in the OnInitialize, you have the initial value of the boolean, so you can make decision here. If you decide to fetch, you are of course warned not to do it right there, because the fetch will hold up the further inialization and further steps of the block buildup. So you need to fetch asynchronously.
One simple trick for this is to use a javascript node with a setTimeout() with a delay of 0. In general, this is a trick to also use if you want to refresh several data actions or aggregates later on in a block or screen lifecycle. They are then no longer automatically asynchrounous (only at start) so using this timeout trick makes them asynchrounous later on (like typically in an OnParametersChanged). Of course only to use if they can do their work independent of each other.
So I am personally massively in favour of option 1 because of it's simplicity, unless you have good reason not to do that.
to be complete, a more sophisticated alternative for the Timeout of option 3, is to use a promise in your OnInitialize that does the refresh.
The difference that I could observe, is that the code in the promise starts executing right away, the code in the Timeout seems to start only after the action it was set in, has done.
Very interesting, Dorine!
I did not know this trick, which indeed can be used in several situations to refresh data actions in parallel. But I am not sure how it works. Should I add the following to my OnInitialize in my case?
setTimeout(function () { $actions.RefreshData();}, 0);
in which RefreshData is a wrapper with the Refresh data action?
Super, thank you Dorine! You solved an issue for that was a brainteaser for me for a while.
In order to make code more readable and prevent copying Javascript I put the Javascript in the wrapper as follows:
I do not use the promise because the calling context (OnInitialize or OnParametersChanged) should end ASAP. The actual refresh may start after that.
Rogier,
Why not set the Fetch parameter of the data action to "At Start", then put the if-statement to read the boolean inside your data action right at the start? Don't forget it to refresh it in the OnParametersChanged.
This way you don't have to juggle with JavaScript, and it provides a clear simple native OutSystems solution I think.
In that case the data action will always be executed, causing a server request, even if not necessary.
I want to prevent executing non-necessary server requests. That is the whole idea of this issue. Decide client side whether the server request is necessary.
Furthermore, the if-statement only works within data actions, not for aggregates.