ux:Global and DataBinding

Dear Fuse-Community :slight_smile:

I wanted to Databind an ux:Global and got this output:

Global objects do not support bindings. Pro tip: Create a ux:Class and create a global instance of that instead.

Sadly im not a “Pro” xD

I defined Global Colors and implemented them in various places in the ux.

All works great and when I change the Global color in the code and recompile the app I see my new “theme”.

Now I wanted to change the color inside my app, to preview different colors without recompiling.

Preferable I would like to have an <TextInput>to define a color.

I simpled everything down to following code:

The commented lines are some tries :confused:

<App>
	<JavaScript>
	var Observable = require("FuseJS/Observable");
	var yzcolor = Observable('#FF0000');
        module.exports = {
            yzcolor: yzcolor
        };
    </JavaScript>
	<SolidColor ux:Global="YZmainColor" Color="#FF0000" />
	<float4 ux:Global="YZmainColorFL" ux:Value="#0000FF" />

<!-- 
	<SolidColor ux:Global="YZmainColor" Color="{yzcolor}" />
	<float4 ux:Global="YZmainColorFL" ux:Value="#0000FF" /> -->


<!-- <SolidColor ux:Class="YZmainColor0" Color="{yzcolor}" />
	<float4 ux:Global="YZmainColorFL" ux:Value="#3b5998" />
	<YZmainColor0 ux:Global="YZmainColor" />
 -->
	<StackPanel>
	<Rectangle Color="YZmainColorFL" Width="100%" Height="50"/>
	<Rectangle Width="100%" Height="50" Background="YZmainColor">
	<Text Value="HelloWorld" Color="YZmainColorFL" />
	</Rectangle>
	<Rectangle Color="YZmainColorFL" Width="100%" Height="50"/>
	<TextInput MaxLength="7" Value="{yzcolor}" />
	<Button Text="Do It">
		<Clicked>
<!-- 			<Set Target="YZmaincolor.Color" Value="{yzcolor}" />
 -->
		</Clicked>
	</Button>
	</StackPanel>
</App>

Any Help would be awesome

Cheers

Blade

I know it is too noob for you all, but for me its a big thing xD
Any help would be awesome

when I change the Global color in the code and recompile the app I see my new “theme”.

Why do you recompile? In preview mode you can just change the color from your text editor and it’ll be updated on the fly.

Yes, but some Parts (like icons inside the native view or mapview) behave different after build.
How could i change the Global from within the app.
Is it possbile?

Gratefully
Blade

In that case I’d implement it as observables exported from a javascript module instead. That’ll make it easy to change from within the app and can easily be made globally available in your app if desired.

OMG thank you soo much for your quick answer. :slight_smile:

Do you have a mini code example for such a noob like me? It doesnt need to fit my codeexample i posted, just a working testcase.

Loving this comunity <3

Cheers

Blade

First of all: It would be really great if you could provide some more info on the cases where changing stuff in preview does not work (you mentioned MapView and icons in NativeView?).

It should work and we really want to know if there are bugs there. :slight_smile:

And for your question:

The simplest example would be something like this, where you type a color value (starting with ‘#’) into a textbox and it updates OutCol which you then use for your components.

	<JavaScript>
		var Observable = require("FuseJS/Observable");
		OutCol = Observable("#f00");
		function SetCol(arg){
			// Input must start with '#' and have a valid number of digits
			l = arg.value.length-1;
			if(l!=3 && l!=4 && l!=6 && l!=8 || arg.value[0]!='#') return;
			OutCol.value = arg.value;
		}
		module.exports = {SetCol, OutCol}
	</JavaScript>
	<ClientPanel>
		<Rectangle Width="100" Height="100" Color="{OutCol}"/>
		<TextBox Dock="Top" PlaceholderText="Type a color value" ValueChanged="{SetCol}"/>
	</ClientPanel>

Important points:

  • You don’t want to bind the value of the text input directly to the out color because preview won’t like it if you try to use an invalid color value (like #f0), which would happen if OutCol was updated in real time.
  • For the same reason I included the simple check in JavaScript. (Please note that this still doesn’t catch invalid colors like #12x, but it should be good enough for just prototyping)
  • To make OutCol available throughout your app it has to be exported at the root level. After all, we’re making a global :slight_smile:

As an exercise I also made a slightly more advanced example here :slight_smile:

AWESOME ANSWER!!!
Remi Pederson, thank you soo much. You cannot imagine, how much I can learn from your two examples.
Sadly I can start working on it tomorrow (and not now), but I will report to you ASAP!!

Also I will retest all the “bugs”/“missing feautures” I found and do a full report with test case code examples.

Very Gratefully

Blade

Hello Remi Pedersen!

Thank you very much. Your two examples are working perfectly.

I swapped all my references to the Global with {vars}.
On the one hand It works really well, on the other hand Im getting an empty redbox with “See Fuse Monitor”.

The output is insane and far beyond my knowledge.
Could you tell me, what that means?

LINK to monitor output

Gratefully

Blade

Hey, I worked on extending it for float4 converting - at least I think I did ^^

Conversion works, but using the color doesn’t: any ideas? :smiley:

var Observable = require("FuseJS/Observable");
YZJSmainColor=Observable("#800000");
YZJScolorHelper=Observable([0.6,0.067,0.33,1]);

 function YZJSmainColorFL(){
 			console.log('YZ_0:'+YZJScolorHelper.value);
				return YZJScolorHelper.value;
			};
 function YZJSmainColorFL2(arg2){
		console.log('YZ_1:'+arg2);

		var h=arg2.replace('#', '');
        h =  h.match(new RegExp('(.{'+h.length/3+'})', 'g'));
        for(var i=0; i<h.length; i++)
             h[i] =  +(Math.round((parseInt(h[i].length==1? h[i]+h[i]:h[i], 16)/255) + "e+2")  + "e-2");
        h.push("1");
        return '['+h.join(',')+']';

			
		};		

function SetCol(arg){
            // Input must start with '#' and have a valid number of digits
            l = arg.value.length-1;
            if(l!=3 && l!=4 && l!=6 && l!=8 || arg.value[0]!='#') return;
            YZJSmainColor.value = arg.value;
        YZJSmainColorFL2(arg.value);
        YZJScolorHelper.value=YZJSmainColorFL2(arg.value);
        console.log('YZ_2:'+YZJScolorHelper.value);
		};
module.exports = {
		SetCol,
                YZJSmainColor,
		YZJSmainColorFL: Observable(YZJSmainColorFL)
	};

Triggering SetCol(#800) does work and gives me this output:

YZ_1:#800

YZ_1:#800

YZ_0:[0.53,0,0,1]

YZ_0:[0.53,0,0,1]

YZ_2:[0.53,0,0,1]

But following by this error while using it:Unable to convert [0.53,0,0,1] to float4 with this output:

Uno.Exception: Unable to convert [0.53,0,0,1] to float4
   at Fuse.Scripting.Marshal.ToFloat4(object)
   at Fuse.Scripting.Marshal.TryConvertTo(Uno.Type,object)
   at Fuse.Scripting.Marshal.TryConvertTo`1(object,T&)
   at Fuse.Reactive.DataBinding`1.TryPushAsMarshalledValue(object)
   at Fuse.Reactive.DataBinding`1.PushValue(object)
   at Fuse.Reactive.DataBinding`1.Fuse.Scripting.IObserver.OnSet(object)
   at Fuse.Scripting.Observable.Set.SendMessage(Fuse.Scripting.Observable.Subscription)
   at Fuse.Scripting.Observable.Operation.Perform()
   at Fuse.Scripting.Context.ProcessUIMessages()
   at Fuse.UpdateListener.Invoke()
   at Fuse.UpdateManager.Update(Fuse.Stage)
   at Fuse.UpdateManager.Update()
   at Fuse.AppBase.OnUpdate()
   at Fuse.App.OnUpdate()
   at Outracks.Simulator.Application.OnUpdate()
   at Fuse.App.OnTick(object,Uno.Platform.TimerEventArgs)
   at Uno.Platform2.Display.OnTick(Uno.Platform.TimerEventArgs)
Unable to convert [0.53,0,0,1] to float4

I know that im a mega noob, im just trying my best. Any help would be awesome

Gratefully

Blade

It looks like you’re returning a string '[0.53,0,0,1]' rather than an array [0.53,0,0,1], which is what you need for the conversion.

Thank you Remi Pedersen <3

Thats, what I was thinking. but there are no ’ or " in my output. So this move:

.replace("\'", "").replace("\'", "");

is not what I want, is it? Or this:

var array = string.split(',');

Any advise for convert string to array?

You shouldn’t need to convert from string to array because the values shouldn’t be in a string form in the first place.
Just make sure YZJSmainColorFL2 returns an array containing 4 numbers.

BOOOOOM, I love you!!! JSON.parse did the trick :smiley:

return JSON.parse('['+h.join(',')+']');

Thank you soo much