Highlighting menu item based on route path

Hi,

I’d like to highlight the menu item, based on current route param.

I have some nested navigation elements, and one of pages MainPage contains PageControl and BottomMenu

When I attach a HistoryChanged handler to PageControl, I receive a build error:

[Viewport]: System.ArgumentException: method argument length mismatch

Below is my code for those components:

MainPage.ux

<Page ux:Class="MainPage">
    <JavaScript>
        const onClickBottomMenu = args => {
            router.push('main', {}, args.button)
        }
        const onClickBanner = args => {
            router.goto('intro')
        }
        function onHistoryChanged() {
            console.log('history changed')
        }
        module.exports = {
            onClickBottomMenu,
            onClickBanner,
            onHistoryChanged
        }
    </JavaScript>
    <Router ux:Dependency="router"/>
    <DockPanel>
        <TopBanner Dock="Top">
            <Clicked Handler="{onClickBanner}" />
        </TopBanner>
        <PageControl HistoryChanged="{onHistoryChanged}">
            <Page ux:Name="store"><Text Value="Store" /></Page>
            <Page ux:Name="cart"><Text Value="Cart" /></Page>
            <Page ux:Name="collect"><Text Value="Collect" /></Page>
            <Page ux:Name="more"><Text Value="Mor<e" /></Page>
        </PageControl>
        <BottomMenu Dock="Bottom" Selected="store">
            <OnClickButton Handler="{onClickBottomMenu}" />
        </BottomMenu>
    </DockPanel>
</Page>

BottomMenu.ux

<Grid ux:Class="BottomMenu" Height="80" Color="#fafafa" ColumnCount="4">
    <string ux:Property="Selected" />
    <JavaScript>
        const items = [{
            path: 'store',
            label: 'Store'
        }, {
            path: 'cart',
            label: 'Cart'
        }, {
            path: 'collect',
            label: 'Collect'
        }, {
            path: 'more',
            label: 'More'
        }]
        module.exports = {
            items
        }
    </JavaScript>
    <UserEvent ux:Name="onClickButton" />
    <OnUserEvent ux:Class="OnClickButton" EventName="onClickButton" />
    <Each Items="{items}">
        <Rectangle HitTestMode="LocalBounds">
            <Text Value="{label}" Alignment="Center" />
            <Clicked>
                <RaiseUserEvent EventName="onClickButton">
                    <UserEventArg Name="button" StringValue="{path}" />
                </RaiseUserEvent>
            </Clicked>
        </Rectangle>
    </Each>
</Grid>

That’s an interesting approach you’ve taken. It would be great to know the path that lead you to doing this.

Either way, you’re not on the right path. From what I can tell, your use case should suffice with just a PageIndicator. We even have a number of examples using it, such as this one.

Let us know if this helps!

I am a React developer, so my habits come from that environment, where unidirectional data flow and dumb components are common pattern.

Actually I was able to achieve what I wanted in that way:

Every page from PageControl sets bottom menu selected item:

            <Page ux:Name="cart">
                <WhileActive Threshold="0.01">
                    <Set bottomMenu.Selected="cart" />
                </WhileActive>
                <Text Value="Store" />
            </Page>

And in bottom menu I map through items and check if it’s path equals Selected param:

    <Each Items="{items}">
        <Rectangle HitTestMode="LocalBounds" ux:Name="btn" Color="{colors.white}">
            <Match Value="{= {path}=={Property Selected}}">
                <Case Bool="True">
                    <Image>
                        <MultiDensityImageSource>
                            <FileImageSource Density="1" File="{iconActive}" />
                            <FileImageSource Density="2" File="{iconActive2x}" />
                            <FileImageSource Density="3" File="{iconActive3x}" />
                        </MultiDensityImageSource>
                    </Image>
                </Case>
…

The only thing I am not totally happy is a delay between pressing a button and setting it as selected, since the event fires when page becomes active, not when the route changes.

Also, I didn’t find a way to simplify that part of code, I feel it must be a way to do it with some inline conditional operatos maybe:

<Match Value="{= {path}=={Property Selected}}">
                <Case Bool="True">...