Controlling preset from another file

Hey guys,

I know that I can’t control a page from another page-file but I am still asking myself if the following, somehow, is possible:

I am currently having a button preset, defined in my Main.ux:

  <Panel ux:Class="DefaultButton">
    <Rectangle ux:Name="Button" Color="#F2F2F2" CornerRadius="25">
      <string ux:Property="Text" />
      <Text ux:Name="ButtonText" Font="Lato" Value="{ReadProperty Text}" Color="#02BBC2" Alignment="Center" Margin="30,15" Opacity="1"/>
    </Rectangle>

    <WhilePressed>
      <Change Button.Color="#D9D9D9" Duration="0.35" DurationBack="0.35" />
    </WhilePressed>
  </Panel>

I want to integrate a loading-animation state where the text switches its opacity and a circle

        <Busy IsActive="false" ux:Name="busy"/>
        <Circle ux:Name="ButtonLoader" Width="45" Height="45" StartAngleDegrees="-45" EndAngleDegrees="45" Opacity="0" ZOffset="1.0">
          <Stroke Width="2" Color="#02BBC2" />
        </Circle>

is spinning when triggering busy.activate(); in my JS-File with:

      <WhileBusy>
        <Spin Target="ButtonLoader" Frequency="1"/>
        <Change Target="ButtonLoader.Opacity" Value="1"/>
      </WhileBusy>

As I mentioned, I integrated the Button preset in my Main.ux and I am calling it from another UX-Page-File with <DefaultButton ux:Name="PageButton" Text="text" Clicked="{text}"/>

Is there any way I can integrated the Busy-Animation in the preset and assign the busy-state from the other UX-File?

It’s somewhat hard to follow through the snippets you posted. Would you mind sharing a complete, minimal reproduction that highlights the challenge you have? You should be able to make a single-UX file app for that.

Basically, I have two different UX-Files.

I have my Main.ux with a defined Button-Preset. And in my Main.ux, I am calling other pages with the Navigator:

Main.ux:

<App>
  <Panel ux:Class="DefaultButton">
    <Rectangle ux:Name="Button" Color="#F2F2F2" CornerRadius="25">
      <string ux:Property="Text" />
      <Text ux:Name="ButtonText" Font="Lato" Value="{ReadProperty Text}" Color="#02BBC2" Alignment="Center" Margin="30,15" Opacity="1"/>
    </Rectangle>

    <WhilePressed>
      <Change Button.Color="#D9D9D9" Duration="0.35" DurationBack="0.35" />
    </WhilePressed>
  </Panel>

<Router ux:Name="router" />

<DockPanel>
    <Navigator DefaultPath="login">
        <firstPage ux:Template="login" router="router" />
        <secondPage ux:Template="home" router="router" />
    </Navigator>
</DockPanel>
</App>

Inside my other pages, I am calling my Buttonpreset in the following way, which is working fine. I also integrated a circle here:

firstPage.ux:

<Page ux:Class="firstPage">
    <Router ux:Dependency="router" />
    <StackPanel>
        <DefaultButton>
           <Busy IsActive="false" ux:Name="busy"/>
           <Circle ux:Name="ButtonLoader" Width="45" Height="45" StartAngleDegrees="-45" EndAngleDegrees="45" Opacity="0" ZOffset="1.0">
           <Stroke Width="2" Color="#02BBC2" />
        </Circle>
        </DefaultButton>
    </StackPanel>
</Page>

Whenever I activate the busy-state from my firstPage.js with busy.activate() I make my added circle visible and spin it:

firstPage.ux

      <WhileBusy>
        <Spin Target="ButtonLoader" Frequency="1"/>
        <Change Target="ButtonLoader.Opacity" Value="1"/>
      </WhileBusy>

This is all working well.
But I don’t want to add the circle every time I am calling my preset.
I am searching for a way to add the circle to my preset.
But I don’t know how to change the opacity and activate the spin when calling a preset which is defined in another UX (my Main.ux).

Is there any way to do this?
I hope it is now easier to follow my code :slight_smile:

You don’t need to use WhileBusy for this in the first place. All you need is your button component to know when it’s in a “loading” state. That can be achieved easily by using ux:Property.
Just like you have your <string ux:Property="Text" /> in there, you can have a boolean property to handle the state:

<Panel ux:Class="DefaultButton" Margin="8" Label="Default Label" isLoading="false">
        <string ux:Property="Label" />
        <bool ux:Property="isLoading" />
        <WhileTrue Value="{ReadProperty isLoading}">
            <Change theLabel.Value="Loading..." />
        </WhileTrue>
        <Text ux:Name="theLabel" Value="{ReadProperty Label}" Color="#02BBC2" Alignment="Center" Margin="16" />
        <Rectangle Color="#F2F2F2" CornerRadius="25" />
    </Panel>

Inside WhileTrue you can describe how the button deviates from its not-busy rest state. For the purpose of this example, we only change the text of the button, but you could also put your Spin in there:

<WhileTrue Value="{ReadProperty isLoading}">
    <Change theLabel.Value="Loading..." />
</WhileTrue>

When you’re done with the button template, you then need to figure out how to change that isLoading property to either true or false. Again, you don’t necessarily need to use a Busy behaviour (while you of course can). Here, we’re creating a JavaScript data context at the root of our application that holds a couple boolean Observables and functions to toggle them:

<JavaScript>
        var Observable = require("FuseJS/Observable");
        var isLoading1 = Observable(false);
        var isLoading2 = Observable(false);
        function firstButton() {
            isLoading1.value = true;
            setTimeout(function() {
                isLoading1.value = false;
            }, 3000);
        }
        function secondButton() {
            isLoading2.value = true;
            setTimeout(function() {
                isLoading2.value = false;
            }, 2400);
        }
        module.exports = {
            isLoading1: isLoading1,
            isLoading2: isLoading2,
            firstButton: firstButton,
            secondButton: secondButton
        };
    </JavaScript>

Now all you need to do is use your button template and make two instances of that button, and data-bind the isLoading property to the right variables:

    <StackPanel Alignment="VerticalCenter">
        <DefaultButton isLoading="{isLoading1}" Clicked="{firstButton}" />
        <DefaultButton Label="My first button" isLoading="{isLoading2}" Clicked="{secondButton}" />
    </StackPanel>

As for the animation part, please check out the answer given in this thread, it looks much smoother that way. Here’s the full code of this example for reference:

<App>
    <Panel ux:Class="DefaultButton" Margin="8" Label="Default Label" isLoading="false">
        <string ux:Property="Label" />
        <bool ux:Property="isLoading" />
        <WhileTrue Value="{ReadProperty isLoading}">
            <Change theLabel.Value="Loading..." />
        </WhileTrue>
        <Text ux:Name="theLabel" Value="{ReadProperty Label}" Color="#02BBC2" Alignment="Center" Margin="16" />
        <Rectangle Color="#F2F2F2" CornerRadius="25" />
    </Panel>
    <JavaScript>
        var Observable = require("FuseJS/Observable");
        var isLoading1 = Observable(false);
        var isLoading2 = Observable(false);
        function firstButton() {
            isLoading1.value = true;
            setTimeout(function() {
                isLoading1.value = false;
            }, 3000);
        }
        function secondButton() {
            isLoading2.value = true;
            setTimeout(function() {
                isLoading2.value = false;
            }, 2400);
        }
        module.exports = {
            isLoading1: isLoading1,
            isLoading2: isLoading2,
            firstButton: firstButton,
            secondButton: secondButton
        };
    </JavaScript>
    <StackPanel Alignment="VerticalCenter">
        <DefaultButton isLoading="{isLoading1}" Clicked="{firstButton}" />
        <DefaultButton Label="My first button" isLoading="{isLoading2}" Clicked="{secondButton}" />
    </StackPanel>
</App>

Hope this helps!

Thank you for this detailed solution!
I will definitely add this to my code.