Router parameters must be serializeable error

Hi,

Ive been following the end-to-end tutorial and trying to place the concepts into my own app. In the tutorial when clicking on a hike it takes you to the details page for that hike by passing the parameters to the router.

In my app i do the same, yet when the clicked element is a custom element it gives me the following error:
Router parameters must be serializeable, cannot contain functions.
I also see the Oops something went wrong screen that gives:
Object reference not sent to an instance of an object.

Below you can see the code I currently have, can anyone tell me if I am doing something incorrectly. Ive console logged the values and they seem to be objects.

console output:
Fuse.Scripting.V8.Object
{“id”:0,“name”:“Squats”,“numSets”:5,“numReps”:5,“weight”:0,“increaseAmount”:1.25,“rest”:90,“barUsed”:true}

Main.ux

<App Background="#E4E4E4">
	<Router ux:Name="router" />

	<ClientPanel>
		<Navigator DefaultPath="listPage">
			<ExerciseListPage ux:Template="listPage" router="router" />
			<ExerciseDetailsPage ux:Template="detailsPage" router="router" />
			<RestPage ux:Template="restPage" router="router" />
		</Navigator>
	</ClientPanel>
</App>

ExerciseDetailsPage.ux

<Panel ux:Class="ExerciseDetailsPage">
	<Router ux:Dependency="router" />

	<JavaScript File="ExerciseDetailsPage.js" /> 

	<TextInput ux:Class="FormInput" FontSize="16" Height="40" PlaceholderColor="#ccc" Margin="10,0,10,0" Padding="10">
	    <Rectangle Layer="Background" CornerRadius="5">
	        <Stroke Width="1" Color="#ccc" />
	        <SolidColor Color="White" />
	    </Rectangle>
	</TextInput>

	<Text ux:Class="FormLabel" FontSize="18" Margin="12,10,0,0" />

	<StackPanel>
		<FormLabel Value="Name:" />
		<FormInput PlaceholderText="Exercise Name" Value="{name}" />

		<FormLabel Value="Weight" />
		<FormInput PlaceholderText="Start Weight" Value="{weight}" InputHint="Decimal" />

		<FormLabel Value="Sets" />
		<FormInput PlaceholderText="Number of Sets" Value="{numSets}" InputHint="Number" />

		<FormLabel Value="Reps" />
		<FormInput PlaceholderText="Number of Reps" Value="{numReps}" InputHint="Number" />

		<FormLabel Value="Rest" />
		<FormInput PlaceholderText="Rest Amount (in seconds)" Value="{rest}" InputHint="Number" />

		<FormLabel Value="Bar Used" />
		<ToggleControl Margin="15,4,15,4" Width="100%" Height="48" Focus.IsFocusable="true" ux:Name="_switch" Value="{barUsed}">
			<Clicked>
				<Toggle Target="_switch" />
			</Clicked>

			<SwipeGesture Direction="Right" Length="38" Type="Active" ux:Name="swipe" IsActive="{Property _switch.Value}" />

			<SwipingAnimation Source="swipe">
		        <Move Target="thumb" X="173"/>
		        <Change trackText.Value="0kg" />
		        <Change trackText.Alignment="CenterLeft" />
		        <Change thumbText.Value="20kg" />
		        <Change thumbText.Color="#fff" />
		        <Change thumbFill.Color="#7BC8EF"/>
		        <Change trackFill.Color="#fff"/>
		        <Change strokeColor.Color="#fff"/>
		    </SwipingAnimation>

			<Panel Layer="Background">
				<Rectangle ux:Name="thumb" Width="50%" Height="34" CornerRadius="23" Alignment="CenterLeft" Margin="4,0,14,0">
					<Text ux:Name="thumbText" Value="0kg" Alignment="Center" Color="#999" />
					<SolidColor ux:Name="thumbFill" Color="#eee" />
					<DropShadow Angle="90" Distance="0" Size="2" Spread="0.05" />
				</Rectangle>

				<Rectangle CornerRadius="23" Width="100%" Height="40" Alignment="Center">
					<Text ux:Name="trackText" Value="20kg" Alignment="CenterRight" Color="#999" Margin="80,0,80,0" />
					<SolidColor ux:Name="trackFill" Color="#ffffff00" />
					<Stroke>
						<SolidColor ux:Name="strokeColor" Color="#ffffffff" />
					</Stroke>
				</Rectangle>
			</Panel>

			<WhileDisabled>
				<Change thumbFill.Color="#bdbdbdff" Easing="QuadraticInOut" Duration="0.25" />
    			<Change trackFill.Color="#0000001e" Easing="QuadraticInOut" Duration="0.25" />
			</WhileDisabled>
		</ToggleControl>

		<FormLabel Value="Increase Amount" />
		<FormInput PlaceholderText="Increase Weight Amount" Value="{increaseAmount}" InputHint="Decimal" />

		<StackPanel Orientation="Horizontal">
			<Panel ux:Class="gymRat.Button" Margin="10" Padding="10">
				<string ux:Property="Text" />

				<Rectangle Layer="Background" Color="#7BC8EF" CornerRadius="4">
					<DropShadow Angle="90" Distance="1" Spread="0.2" Size="2" Color="#00000060" />
				</Rectangle>

				<Text Value="{ReadProperty Text}" Color="White" FontSize="16" TextAlignment="Center" />

				<WhilePressed>
					<Scale Factor=".95" Duration=".08" Easing="QuadraticOut" />
				</WhilePressed>
			</Panel>

			<gymRat.Button Text="Cancel" Clicked="{cancel}" />
			<gymRat.Button Text="Save" Clicked="{save}" />
		</StackPanel>
	</StackPanel>
</Panel>

ExerciseDetailsPage.js

var Observable = require("FuseJS/Observable");
var Context = require("Modules/Context");

var exercise = this.Parameter;

var name 			= exercise.map(function(x) { return x.name; });
var weight 			= exercise.map(function(x) { return x.weight; });
var numSets			= exercise.map(function(x) { return x.numSets; });
var numReps			= exercise.map(function(x) { return x.numReps; });
var rest			= exercise.map(function(x) { return x.rest; });
var barUsed			= exercise.map(function(x) { return x.barUsed; });
var increaseAmount 	= exercise.map(function(x) { return x.increaseAmount; });

function save() {
	if (exercise.value.id >= 0) {
		Context.updateExercise(exercise.value.id, name.value, weight.value, numSets.value, numReps.value, rest.value, barUsed.value, increaseAmount.value);
	} else {
		Context.createExercise(name.value, weight.value, numSets.value, numReps.value, rest.value, barUsed.value, increaseAmount.value);
	}
	
	router.goBack();
}

function cancel() {
	exercise.value = exercise.value;
	router.goBack();
}

module.exports = {
	name: name,
	weight: weight,
	numSets: numSets,
	numReps: numReps,
	rest: rest,
	barUsed: barUsed,
	increaseAmount: increaseAmount,

	save: save,
	cancel: cancel
};

ExerciseListPage.ux
note: using the commented section this doent give the error but my custom exercise component contains other functionality that I require

<Panel ux:Class="ExerciseListPage">
	<Router ux:Dependency="router" />
	
	<JavaScript File="ExerciseListPage.js" />

	<DockPanel>
		<StackPanel Dock="Top" Color="#515153">
			<StatusBarBackground />
			<Panel Height="56">
				<Panel Alignment="Right" HitTestMode="LocalBounds" Width="56" Height="56" Clicked="{createExercise}">
					<Rectangle Height="2" Width="20" Color="#fff" />
					<Rectangle Width="2" Height="20" Color="#fff" />
				</Panel>
			</Panel>
			<Shadow Distance="1" Size="3" />
		</StackPanel>
		
		<WhileEmpty Items="{exercises}">
			<StackPanel ux:Name="emptyView" Alignment="Center" ItemSpacing="20">
				<Text Alignment="Center" FontSize="20">Nothing to see here</Text>
				<Text Alignment="Center">Add an exercise using the button above</Text>

				<AddingAnimation>
					<Change emptyView.Opacity="0" Duration="0.2" />
					<Scale Factor="0.4" Duration="0.4" Easing="CubicInOut" />
				</AddingAnimation>				
				<RemovingAnimation>
					<Change emptyView.Opacity="0" Duration="0.2" />
				</RemovingAnimation>
			</StackPanel>
		</WhileEmpty>

		<ScrollView>
			<StackPanel>
				<Each Items="{exercises}">
					<!--
					<Panel Width="100%" Height="120" Margin="10">
						<Rectangle Color="#fff" Layer="Background" CornerRadius="5" />

						<Panel Alignment="Top" HitTestMode="LocalBoundsAndChildren" Clicked="{goToExercise}">
							<Text Alignment="Left" FontSize="18" Color="#000" Margin="18,15,0,0" Value="{name}" /> 
							<Text Alignment="Right" FontSize="14" Color="#000" Margin="0,18,18,0" Value="{weight} kg" />
						</Panel>
						<StackPanel Orientation="Horizontal" Alignment="BottomCenter" Margin="5">
						    <Each Count="{numSets}">
						        <Reps MaxCount="{numReps}" BgColor="#7BC8EF">
						        	<OnUserEvent EventName="completed" Handler="{completed}"/>
						        </Reps>
						    </Each>
						</StackPanel>
					</Panel>
				-->

					<Exercise ux:Name="exercise" Id="{id}" ExerciseName="{name}" Weight="{weight}" NumSets="{numSets}" NumReps="{numReps}" Rest="{rest}" IncreaseAmount="{increaseAmount}" BarUsed="{barUsed}">
						<OnUserEvent EventName="startRest" Handler="{startTimer}" />
						<OnUserEvent EventName="updateExercise" Handler="{goToExercise}" />

						<AddingAnimation>
							<Change exercise.Opacity="0" Duration="0.3" />
						</AddingAnimation>
						<RemovingAnimation>
							<Change exercise.Opacity="0" Duration="0.1" />
						</RemovingAnimation>
						<LayoutAnimation>
							<Move Y="1" RelativeTo="PositionChange" Duration="0.15" Easing="CubicInOut" />
						</LayoutAnimation>
						<Shadow Distance="3" Size="2" Angle="120" />
					</Exercise>
				</Each>
			</StackPanel>
		</ScrollView>
	</DockPanel>
</Panel>

ExerciseListPage.js

var Observable = require("FuseJS/Observable");
var Context = require("Modules/Context");

function goToExercise(arg) {
	var exercise = arg.data;
	console.log(exercise);
	console.log(JSON.stringify(exercise));
	router.push("detailsPage", exercise);
}

function createExercise() {
	var exercise = {};
	router.push("detailsPage", exercise);
}

startTimer = function(args) {
	var rest = args.data.rest._values[0];
	router.push('restPage', rest);
}

module.exports = {
	exercises: Context.exercises,

	goToExercise: goToExercise,
	createExercise: createExercise,
	startTimer: startTimer
};

Thanks in advance.

Hi kvhauw,

the root cause of your problem is what the error message states - router parameters have to be serializeable. To explain: objects can contain functions and functions can not be serialized. Same applies to Observables, which happen to be objects with associated functions.

So the problem manifests itself, most likely, on one of these lines:

router.push("detailsPage", exercise);
router.push('restPage', rest);

simply because either your Context.exercises is a list of objects that have an Observable property (or a few), or because the rest variable is an Observable. You can not pass Observables via router.

Your best bet would be to only pass an ID that identifies a particular entity (a given exercise in your case), and pulling the necessary information from the Context module on the target page, instead of passing all of the object to the page.

Hope this helps!

Thanks for the explanation,

I will try as you suggested to just pass the id and see if i can get it to work this way.

Many thanks