7
Views
2
Comments
Solved by AI
LoadingButton not showing loading state inside Popup block (UI not updating)

Note: This text was translated into English using AI. Please excuse any unnatural phrasing.

I have created a reusable block that only displays a Popup, and I am using it across multiple screens. 

Inside this block, I placed a LoadingButton. When the button is pressed, the following logic is implemented: 

  1. Set a loading state variable to True 
  2. Trigger an event to notify the parent screen 
  3. Set the Popup display variable to False to close the Popup 

However, the behavior is not as expected, and the following issues occur: 

  • The loading animation is not displayed when the button is pressed 
  • The Popup does not close until the parent screen’s event handler finishes execution 
  • The button can be clicked multiple times until the Popup closes (multiple executions occur) 

Ideally, I expect the button to immediately enter a loading state on click, disable further interaction, and then close the Popup.

What I have tried

  • Set a variable on the Button’s Enabled property and changed it to False immediately after the button is clicked
    → No change in behavior (the button can still be clicked multiple times without restriction) 
  • Wrapped the button in a container, set a variable on the container’s Visible property, and changed it to False immediately after the button is clicked
    → The button remains visible.

Questions

  • In this setup (Popup inside a block + event notification to the parent screen), what could be causing the LoadingButton and UI updates not to be applied?
  • What is the recommended way to ensure the loading state is shown immediately and prevent multiple clicks?
  • Are there best practices for controlling the timing between closing the Popup and executing the parent event handler?


2023-12-26 10-35-28
OutSystems Neo
Staff
Solution by AI
AI Generated

The behavior you’re seeing is expected in ODC with blocks + events: all client logic (including UI updates) is executed as one “transaction” before the screen is re‑rendered, and once you trigger a block event, control moves to the parent flow. That’s why:

Below is how to fix this and what pattern to use.


1. Why the LoadingButton and UI updates don’t apply

When you do this inside the block:

  1. IsLoading = True
  2. Trigger Event to parent
  3. IsPopupVisible = False

the event immediately transfers execution to the parent action, so steps 1 and 3 never get a chance to be reflected in the UI before the long‑running logic completes. ODC: Button Loading inside block doesn't show spinner when calling a block event

This is the same situation described in the article you referenced: the “loading” logic needs to run where the actual work is being done (i.e., in the parent), not in the publisher block. ODC: Button Loading inside block doesn't show spinner when calling a block event


Use an input parameter (e.g., IsSaving) on the event and manage the loading state in the parent that subscribes to the event. This is the same pattern suggested in the forum solution. ODC: Button Loading inside block doesn't show spinner when calling a block event

Step‑by‑step restructuring

In the Block:

  • Do not set IsLoading or close the Popup inside the block’s click handler.
  • The block only:
    • Raises the event.
    • Uses input parameters for:
      • IsSaving (Boolean) → bound to LoadingButton.IsLoading and Button.Enabled.
      • IsVisible (Boolean) → bound to the Popup’s visibility or input of the popup widget.

So something like:

  • Block Inputs:
    • IsSaving: Boolean
    • IsVisible: Boolean
  • Button:
    • ButtonLoading.IsLoading = IsSaving
    • Button.Enabled = not IsSaving
  • Popup:
    • Visible = IsVisible
  • OnClick of button:
    • Only trigger OnConfirm event (no local assigns).

In the Parent Screen:

  • Have local variables:

    • Popup_IsVisible: Boolean
    • Popup_IsSaving: Boolean
  • Bind block inputs:

    • IsVisible = Popup_IsVisible
    • IsSaving = Popup_IsSaving
  • In the parent’s event handler (subscriber):

    1. Popup_IsSaving = True
      (Loading spinner appears & button is disabled before any heavy logic runs.)

    2. Execute your long‑running logic:

      • Call server actions, timers, etc.
    3. When finished:

      • Popup_IsSaving = False
      • Popup_IsVisible = False (close the popup)

If needed, set Popup_IsSaving = False also in exception handling, like communication errors, so the UI does not remain stuck in loading. Prevent users from spam clicking buttons

This way:

  • The loading state is controlled where the work happens.
  • Button is disabled by IsSaving → prevents multiple clicks.
  • Popup close is explicitly controlled at the end of the parent logic.

This is effectively the same pattern you use in other “prevent multiple clicks” scenarios (boolean bound to Enabled + LoadingButton), just split between block and parent. Prevent user from clicking too fast on several buttons and links


3. Why your “Enabled” and “Visible” toggles didn’t work

When you tried:

  • Button.Enabled = SomeLocalFlag then set it to False inside the block, or
  • Container.Visible = SomeFlag and set it to False,

you still had the same problem: the assigns occur in the same client‑side execution cycle as the event trigger. The UI only re‑renders after the entire chain (block + parent event) finishes. So you cannot rely on local block state changing after the event has been triggered and expect an immediate visual update.

That’s why the fix is to:

  • Move the state ownership (IsSaving, IsVisible) to the top‑level container (parent screen),
  • And have the block only reflect that state via inputs instead of trying to control it internally.

4. Best practices for popup closing vs parent execution timing

Depending on UX requirements, you have a few patterns:

  1. Close popup after all processing completes (simplest)

    • As described above: show loading + disable button, run logic, then close popup at the end.
    • Good when user must wait for the operation to finish.
  2. Close immediately, process in background

    • In parent event handler:
      • Immediately set Popup_IsVisible = False
      • Optionally show a page‑level loading overlay or “toast” saying “Processing…”
      • Then run the heavy logic.
    • Useful if you want the screen “released” quickly.
  3. Global “overlay” to block everything

Whichever you choose, keep the rule: UI state is handled at the consumer (parent), not inside the reusable block once events are involved. This matches the recommended approach in the referenced ODC thread and is what will make your LoadingButton behave correctly. ODC: Button Loading inside block doesn't show spinner when calling a block event

This answer was AI-generated. Please read it carefully and use the forums for clarifications
UserImage.jpg
明典 島田

Thanks, OutSystems Neo! 
This solution resolved my issue. The key was moving the loading state management to the parent screen instead of the block.

Community GuidelinesBe kind and respectful, give credit to the original source of content, and search for duplicates before posting.