Proper parameter passing between ux files

Hi,

I have the following setup:

  • a) ListPage.ux with several items

  • b) DetailsPage.ux displaying items details

  • c) TopBar.ux as a component placed in my DetailsPage.ux

  • d) ImageHolder.ux a component in the TopBar which places a corresponding image depending on the imageName parameter

The list of items has a {name}and an {imageName} Parameter. Those work fine in my list.
When I click my Item, a detailed view of the item is displayed.
I receive the data from the list in my details this way:

var name = taking.pickTwoWay("name"); 
var imageName = taking.pickTwoWay("imageName"); 

I export these variables and use the further on in my DetailsPage.ux

On my detail page I call my <TopBar />this way

<TopBar Text="{name}" imageName="{imageName}" />

When logging the passed parameters from TopBar.ux this way:

<Activated>
	<DebugAction Message="activated {Property topBar.Text} with {Property topBar.imageName}" />
</Activated>

I can check the data passed to my TopBar.

Now imagine I have two items in my list.

  • item 1

    • name : a
    • imageName : a1
  • item 2

    • name : b
    • imageName : b1

When selecting one item, then switching back and selecting another one the data passing ends up being totally chaotic.
After several switches between my Items I pass completely wrong parameters, when it comes to the log.

When clicking item 2, the log tells me Name is a and imageName is a1. But the correct values (b) are displayed in my detail fields.
However passing the imageName (b1) to my ImageHolder.ux this way:

<ImageHolder ImageName="{Property topBar.imageName}"  />
```

displays always an image which corresponds to the logged data (in this case a1). 
I feel like there is a discrepancy in the processing of my data. Or I am just doing it completely wrong :)

Thank you in advance

Edit: I've been able to narrow it down a bit. I see that my TopBar.ux receives always the last parameters, which have been passed to the item. Not the current ones but from the item I clicked before.

Edit 2: it looks like passing my imageName parameter through all the components takes too long. Working on a solution for this.

Hi Maksym!

Could you please post a full example? It’d be far easier to see the problem and suggest a solution when running the actual code you have.

I am sorry. As its a company project I am working on, I cannot provide the full code. But I hope this will suffice:

<Rectangle ux:Class="TopBar" ux:Name="topBar" Dock="Top" Height="56" Margin="0,0,0,3" Text=""  imageName="" >

	<string ux:Property="Text" />
	<string ux:Property="imageName"/>

	<Activated>
		<DebugAction Message="activated {Property topBar.Text} with {Property topBar.imageName}" />
		<!-- these are empty at this point, as stated in the default parameters above -->
	</Activated>

<StackPanel ItemSpacing="5">
	<!-- this one does not get displayed correctly on initial load and is always offset by one -->
	<ImageHolder imageName="{Property topBar.imageName}"  Margin="20"/>

	<Panel Width="80%" Alignment="Center">
	<!-- the name is ALWAYS correct -->
		<BoldText Value="{Property topBar.Text}" FontSize="20" TextColor="#fff" Alignment="Center" TextWrapping="Wrap"/>
	</Panel>
</StackPanel>

</Rectangle>

The ImageHolder.ux looks this way:

<Panel ux:Class="ImageHolder" ux:Name="imageHolder" Width="50" Height="50" imageName="">
	<!-- the js processes the name and sets  -->
	<JavaScript File="ImageHolder.js" />

	<string ux:Property="imageName" />

	<Panel ux:Name="canvas" Width="100%" Opacity="1">
		
		<WhileTrue Value="{imageVisibility.isA}" >
			<ImageA />
		</WhileTrue>

		<WhileTrue Value="{imageVisibility.isB}" >
			<ImageB />
		</WhileTrue>

	</Panel>

</Panel>

ImageHolder.js

var Model = require ("Utils/Model");
var Observable = require("FuseJS/Observable");

var providedImage = this.imageName;

var imageVisibility	        = Observable(
	{
		isA 	: Observable(false),
		isB 	: Observable(false)
	}
);

switch (providedImage.value){
	case Model.images[0]:
		imageVisibility.value.isA.value = true;
		break;

	case Model.dosageUnits[1]:
		imageVisibility.value.isB.value = true;
		break;

	default:
}

module.exports = {
	imageVisibility : imageVisibility
};

Hey Maksym,

it would have helped tremendously if you would have just made a smaller reproduction in the form of a self-contained, ready-to-run app. I ended up doing that for you, however, I can not be certain that you are not doing something else with the navigation actions involved that you have not shared.

That aside, it seems to me that the main cause behind your issue is how you work with ux:Property. In the JavaScript code you posted, you are expecting providedImage to be available immediately, which, as you correctly found, is not the case. Properties are observables that get populated async, hence you have to use reactive observable operators (such as .map()) to react when the value becomes available.

To avoid such problems in the future, I suggest you do some reading here: https://www.fusetools.com/docs/basics/creating-components#properties-code-ux-property-code

Let’s flush it then:

<App Background="#000">

	<!-- components -->
	<Rectangle ux:Class="TopBar" Background="#FFF1">
	    <string ux:Property="Text" />
	    <string ux:Property="ImageName"/>

		<StackPanel ItemSpacing="5">
		    <ImageHolder ImageName="{ReadProperty ImageName}"  Margin="20"/>
		    <Panel Width="80%" Alignment="Center">
		        <Text Value="{ReadProperty Text}" FontSize="20" TextColor="#fff" Alignment="Center" TextWrapping="Wrap" />
		    </Panel>
		</StackPanel>
	</Rectangle>

	<Panel ux:Class="ImageHolder" Width="50" Height="50">
	    <string ux:Property="ImageName" />

	    <JavaScript>
		var imageVisibility = this.ImageName.map(function(x) {
			var obj = {
				isA: false,
				isB: false
			};
			switch (x){
			    case "a":
			        obj.isA = true;
		        break;
		    	case "b":
			        obj.isB = true;
		        break;
			    default:
			        obj.isA = false;
			        obj.isB = false;
			    break;
			}
			return obj;
		});

		module.exports = {
		    imageVisibility : imageVisibility
		};
	    </JavaScript>


	    <Panel>
	        <WhileTrue Value="{imageVisibility.isA}" >
	            <Image Url="http://printableletters.org/letterswp/wp-content/uploads/large-printable-letter-a.jpg" />
	        </WhileTrue>
	        <WhileTrue Value="{imageVisibility.isB}" >
	            <Image Url="http://printableletters.org/letterswp/wp-content/uploads/large-printable-letter-b.jpg" />
	        </WhileTrue>
	    </Panel>

	</Panel>

	<!-- main app -->
	<JavaScript>
		var Observable = require("FuseJS/Observable");
		var showImage = Observable("a");
		function toggle() {
			if (showImage.value == "a") {
				showImage.value = "b";
			} else {
				showImage.value = "a";
			}
		}
		module.exports = {
			toggle: toggle,
			showImage: showImage
		};
	</JavaScript>
	<DockPanel>
		<TopBar ImageName="{showImage}" Text="To B or not to B" Dock="Top" />
		<Panel>
			<Button Text="Toggle image" Alignment="Center" Width="160" Height="56" Background="#FFF2" Clicked="{toggle}" />
		</Panel>
	</DockPanel>

</App>