[Sugarcube] Nested arrays and multiple for loops

Hi all!

I’m trying to pull items from a nested array, and I’m having trouble displaying the nested items with for loops.

Twine Version: 2.3.9
Story format: SugarCube 2.31.1

Here’s the code:

<<set $items_list = [
{
	name: "item 1",
	subitems: [
	{
		name: "item 1.1",
	}, {
		name: "item 1.2",
	}
	],
}, {
	name: "item 2",
	subitems: [
	{
		name: "item 2.1",
	}, {
		name: "item 2.2",
	}
	],
}
]>>

<span id="selected_item"></span>

<span id="display_items">
	<<for $i = 0; $i < $items_list.length; $i++>>
		<<capture $i>>
			<<link $items_list[$i].name>>
				<<display_subitems>>
			<</link>>
		<</capture>>
	<</for>>
</span>

<span id="display_subitems"></span>

<<widget "display_subitems">>
<<replace "#display_subitems" t8n>>
<<for $j = 0; $j < $items_list[$i].subitems.length; $j++>>
	<<capture $j>>
		<<link $items_list[$i].subitems[$j].name>>
			<<set $items_list[$i].subitems[$j].count += 1>>
			<<replace "#selected_item">>
				items_list[$i].name: $items_list[$i].name
				items_list[$i].subitems[$j].name: $items_list[$i].subitems[$j].name
			<</replace>>
		<</link>>
	<</capture>>
<</for>>
<</replace>>
<</widget>>

I can get $items_list[$i].name and $items_list[0].subitems[0].name displaying properly, but not $items_list[$i].subitems[$j].name.

Thoughts?

If you look at the examples given in the Naked Variable documentation you will see there are limits to how complex a variable reference can be before you need to use one of the <> macros instead.

Also instead of using Story Variables to store the index values of your outer & inner for loops, you can use Temporary variables and pass the outer index as a argument to your <<display_subitems>> widget.

The following is a variation of your own code, it is written using TWEE Notation.

:: Story Widgets [widget nobr]
<<widget "display_subitems">>
	<<set _i to $args[0]>>
	<<replace "#display_subitems" t8n>>
		<<for _j = 0; _j < $items_list[_i].subitems.length; _j++>>
			<<capture _i, _j>>
				<<link $items_list[_i].subitems[_j].name>>
					<<set $items_list[_i].subitems[_j].count += 1>>
					<<replace "#selected_item">>
						<<print $items_list[_i].name>>: <<print $items_list[_i].name>><br>
						<<print $items_list[_i].subitems[_j].name>>: <<print $items_list[_i].subitems[_j].name>>
					<</replace>>
				<</link>>
			<</capture>>
		<</for>>
	<</replace>>
<</widget>>

:: StoryInit
<<set $items_list = [
{
	name: "item 1",
	subitems: [
	{
		name: "item 1.1",
	}, {
		name: "item 1.2",
	}
	],
}, {
	name: "item 2",
	subitems: [
	{
		name: "item 2.1",
	}, {
		name: "item 2.2",
	}
	],
}
]>>

:: Start
<span id="selected_item"></span>
<span id="display_items">
	<<for _i = 0; _i < $items_list.length; _i++>>
		<<capture _i>>
			<<link $items_list[_i].name>>
				<<display_subitems _i>>
			<</link>>
		<</capture>>
	<</for>>
</span>
<span id="display_subitems"></span>
2 Likes

Ah! Thanks for pointing out the Naked Variable limitations. That handled the variable display part. Passing arguments to the widget makes it cleaner as well.

The subitems link text wasn’t showing, but after setting it to a temp variable, it worked.

<<set _k = $items_list[_i].subitems[_j].name>>
<<link _k>>

Thanks again!

That would be because the expression wasn’t being passed to the <<link>> macro properly. The <<link>> macro wants discreet arguments, so if you need to pass a lengthy/complex expression to it, then you either need to use a temporary variable or a backquote expression.

You did the former, so here’s an example of the latter:

<<link `$items_list[_i].subitems[_j].name`>>

SEE: Macro Arguments.

1 Like

Super helpful. Thank you!