Cannot be accessed from this scope

I drew a pie chart with a legend on the inside corner of the screen. When you click on the legend rectangle, the slice of the referenced chart should be highlighted, but it is displaying an error message saying: “piece declared cannot be accessed from this scope”. Heeelp!

<StackPanel ux:Name="allContent" ItemSpacing="20">
	<Panel Height="250">
		<Panel ux:Name="wheelPanel" >
			<Panel ux:Name="wheel" Height="150" Margin="5,35,5,5" >
					<Circle Color="Gray" Width="10%" Height="10%"/>
					<Each Items="{items}">
						<Circle ux:Name="piece" Color="{color}" StartAngleDegrees="{startAngle}" EndAngleDegrees="{endAngle}" Opacity="0.4" Layer="Layout">
							<WhileHovering>
								<Change piece.Opacity="1" Duration="0.2"/> 
								<DropShadow/>
							</WhileHovering>
						</Circle>
					</Each>
					<Panel ux:Name="mainContent" Opacity="1" Margin="0,250,0,0"  Layer="Layout"  Height="50%" Alignment="Bottom"  >
						<StackPanel>
							<Each Items="{items}">
								<Rectangle Margin="10,2,10,2"  >																
									<WhileHovering>
											<Change piece.Opacity="1" Duration="0.2"/>
										<Scale Factor="1.2" Duration="0.1" />
									</WhileHovering>
								</Rectangle>
								<Text Value="Client_Name + %"  Color="White" FontSize="18"  Margin="40,10,0,0" Opacity="1"/>
								<DropShadow/>														
								</Rectangle>
							</Each>
						</StackPanel>	
				</Panel> 
			</Panel>
		</Panel>
	</Panel>
</StackPanel>

Could you please post a complete reproduction that also includes the necessary JS data to draw the actual pie chart? Although the problem is clear, it’s very hard to help without seeing anything.

As for the problem. Things that get generated inside an Each get an implicit data context and you can not access them from outside, which you appear to be doing on this line: <Change piece.Opacity="1" Duration="0.2"/>. Exactly what the error said.

I could try to fix the code for you, but can not do that without a complete repro.

<App Background="#192050">
	<iOS.StatusBarConfig Style="Light" />
		<JavaScript File="MainView.js"/>
			<DropShadow/>
			<StackPanel ux:Name="allContent" ItemSpacing="20">
				<Panel Height="250">
					<Panel ux:Name="wheelPanel" >
						<Panel ux:Name="wheel" Height="150" Margin="5,35,5,5" >
								<Circle Color="Gray" Width="10%" Height="10%"/>
								<Each Items="{items}">
									<Circle ux:Name="piece" Color="{color}" StartAngleDegrees="{startAngle}" EndAngleDegrees="{endAngle}" Opacity="0.4" Layer="Layout">
										<WhileHovering>
											<Change piece.Opacity="1" Duration="0.2"/> 
											<DropShadow/>
										</WhileHovering>
									</Circle>
								</Each>
								<Panel ux:Name="mainContent" Opacity="1" Margin="0,250,0,0"  Layer="Layout"  Height="50%" Alignment="Bottom"  >
									<StackPanel>
										<Each Items="{items}">
											<Rectangle Margin="10,2,10,2"  >																
												<Rectangle  Alignment="Left"  Color="{color}" Height="25" CornerRadius="7" Width="25" Layer="Overlay"><Selectable Value="{color}" />			
													<WhileHovering>
<!-- 															<Change piece.Opacity="1" Duration="0.2"/>
 -->															<Scale Factor="1.2" Duration="0.1" />
													</WhileHovering>
												</Rectangle>
												<Text Value="Client_Name + %"  Color="White" FontSize="18"  Margin="40,10,0,0" Opacity="1"/>
												<DropShadow/>														
											</Rectangle>
										</Each>
									</StackPanel>	
							</Panel> 
						</Panel>
					</Panel>
				</Panel>
		</StackPanel>
</App>

MainView.js:

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

var items = Observable([
	{ value: 25, color: "#4CD8FC" },
	{ value: 15, color: "#A943C1" },
	{ value: 30, color: "#FFCE6B" },
	{ value: 10, color: "#EB4CAF" },
	{ value: 20, color: "#33CB9F" }
]);

var currentPage = Observable(0);

function activated(arg) {
	currentPage.value = arg.data.index;
}

var defaultRotation = Observable(0);
module.exports = {
	items: items.map(function(i){
		var lastItem = {
			startAngle: 0,
			endAngle: 0,
			angle: 0
		};
		i.forEach(function(x, c) {
			x.index = c;
			x.angle = ((x.value / 100) * 360);
			if (c === 0) {
				defaultRotation.value = x.angle / 2 + 90;
				lastItem.wheelRotate = 0;
			}
			if (c > 0) {
				lastItem.wheelRotate = (x.angle / 2) + (lastItem.angle / 2);
			}

			x.startAngle = lastItem.startAngle - x.angle;
			x.endAngle = lastItem.startAngle;

			x.isActive = Observable(function(){
				return currentPage.value == x.index;
			});

			lastItem = x;

		});
		return i;
	}).expand(),
	currentPage: currentPage,
	activated: activated,
	defaultRotation: defaultRotation
};

Alright, now this makes much more sense. You want to change the state of the iterated items from two different Each contexts.

To do that, you need to put something in the middle that links the two contexts. I see a reference to Selection, so it seems that you’ve kind of figured that out yourself.

Here’s one take on it, using Selection, that almost works (I wouldn’t use WhileHovering if I were you):

<App Background="#192050">
    <iOS.StatusBarConfig Style="Light" />
    <JavaScript>
    var Observable = require("FuseJS/Observable");

    var items = Observable([
        { value: 25, color: "#4CD8FC" },
        { value: 15, color: "#A943C1" },
        { value: 30, color: "#FFCE6B" },
        { value: 10, color: "#EB4CAF" },
        { value: 20, color: "#33CB9F" }
    ]);

    var mappedItems = items.map(function(i){
        var lastItem = {
            startAngle: 0,
            endAngle: 0,
            angle: 0
        };
        i.forEach(function(x, c) {
            x.index = c;
            x.angle = ((x.value / 100) * 360);
            if (c === 0) {
                defaultRotation.value = x.angle / 2 + 90;
                lastItem.wheelRotate = 0;
            }
            if (c > 0) {
                lastItem.wheelRotate = (x.angle / 2) + (lastItem.angle / 2);
            }

            x.startAngle = lastItem.startAngle - x.angle;
            x.endAngle = lastItem.startAngle;

            x.isActive = Observable(function(){
                return currentPage.value == x.index;
            });

            lastItem = x;

        });
        return i;
    }).expand();

    var currentPage = Observable(0);

    function activated(arg) {
        currentPage.value = arg.data.index;
    }

    var defaultRotation = Observable(0);
    module.exports = {
        items: mappedItems,
        currentPage: currentPage,
        activated: activated,
        defaultRotation: defaultRotation
    };
    </JavaScript>

    <DockPanel ux:Name="allContent">
        <Panel ux:Name="wheelPanel" Dock="Top" Height="250">
            <Panel ux:Name="wheel" Height="150">
                <Circle Color="Gray" Width="10%" Height="10%"/>
                <Selection ux:Name="wheelSelection" MaxCount="1" />
                <Each Items="{items}">
                    <Circle ux:Name="piece" Color="{color}" StartAngleDegrees="{startAngle}" EndAngleDegrees="{endAngle}" Opacity="0.4">
                        <Selectable Value="{color}" />
                        <WhileSelected>
                            <Change piece.Opacity="1" Duration="0.2"/>
                        </WhileSelected>
                        <WhileHovering>
                            <ToggleSelection />
                        </WhileHovering>
                    </Circle>
                </Each>
            </Panel>
        </Panel>
        <Panel ux:Name="mainContent">
            <StackPanel Alignment="Center" Margin="10" ItemSpacing="4">
                <Each Items="{items}">
                    <DockPanel>
                        <Rectangle Dock="Left" Color="{color}" Height="25" CornerRadius="4" Width="25">
                            <WhileHovering>
                                <Change wheelSelection.Value="{color}" />
                                <Scale Factor="1.2" Duration="0.1" />
                            </WhileHovering>
                        </Rectangle>
                        <Text Value="Client_Name + %" Color="White" FontSize="18" Alignment="VerticalCenter" Margin="10,0" />
                    </DockPanel>
                </Each>
            </StackPanel>   
        </Panel> 
    </DockPanel>
</App>

If I was making something like this, I would be feeding the state change through JavaScript callbacks on the iterated objects themselves. But this approach is really basically the same as using Selection API. But here, I fixed your Observables syntax, so take a close look:

<App Background="#192050">
    <iOS.StatusBarConfig Style="Light" />
    <JavaScript>
    var Observable = require("FuseJS/Observable");

    var items = Observable(
        new Item(25,"#4CD8FC"),
        new Item(15,"#A943C1"),
        new Item(30,"#FFCE6B"),
        new Item(10,"#EB4CAF"),
        new Item(20,"#33CB9F")
    );

    function Item(value, color) {
        this.value = value;
        this.color = color;
        this.isSelected = Observable(false);
        var self = this;
        this.setSelected = function() {
            items.forEach(function(i) {
                i.isSelected.value = false;
            });
            self.isSelected.value = true;
        };
    }

    var lastItem = {
        startAngle: 0,
        endAngle: 0,
        angle: 0
    };

    var mappedItems = items.map(function(x, c){
        x.index = c;
        x.angle = ((x.value / 100) * 360);
        if (c === 0) {
            defaultRotation.value = x.angle / 2 + 90;
            lastItem.wheelRotate = 0;
        }
        if (c > 0) {
            lastItem.wheelRotate = (x.angle / 2) + (lastItem.angle / 2);
        }

        x.startAngle = lastItem.startAngle - x.angle;
        x.endAngle = lastItem.startAngle;

        x.isActive = Observable(function(){
            return currentPage.value == x.index;
        });

        lastItem = x;
        return x;
    });

    var currentPage = Observable(0);

    function activated(arg) {
        currentPage.value = arg.data.index;
    }

    var defaultRotation = Observable(0);
    module.exports = {
        items: mappedItems,
        currentPage: currentPage,
        activated: activated,
        defaultRotation: defaultRotation
    };
    </JavaScript>

    <DockPanel ux:Name="allContent">
        <Panel ux:Name="wheelPanel" Dock="Top" Height="250">
            <Panel ux:Name="wheel" Height="150">
                <Circle Color="Gray" Width="10%" Height="10%"/>
                <Each Items="{items}">
                    <Circle ux:Name="piece" Color="{color}" StartAngleDegrees="{startAngle}" EndAngleDegrees="{endAngle}" Opacity="0.4">
                        <WhileHovering>
                            <Callback Handler="{setSelected}" />
                        </WhileHovering>
                        <WhileTrue Value="{isSelected}">
                            <Change piece.Opacity="1" Duration="0.2"/>
                        </WhileTrue>
                    </Circle>
                </Each>
            </Panel>
        </Panel>
        <Panel ux:Name="mainContent">
            <StackPanel Alignment="Center" Margin="10" ItemSpacing="4">
                <Each Items="{items}">
                    <DockPanel>
                        <Rectangle Dock="Left" Color="{color}" Height="25" CornerRadius="4" Width="25">
                            <WhileHovering>
                                <Callback Handler="{setSelected}" />
                                <Scale Factor="1.2" Duration="0.1" />
                            </WhileHovering>
                        </Rectangle>
                        <Text Value="Client_Name + %" Color="White" FontSize="18" Alignment="VerticalCenter" Margin="10,0" />
                    </DockPanel>
                </Each>
            </StackPanel>   
        </Panel> 
    </DockPanel>
</App>

Hope this helps!