Dinamically set name of tabs from JSON data

It’s long time I’m trying to work out this issue. I would like to create a number of tabs based on the data fetched from a API in JSON format. The number of tabs is not fixed but it depends on the data downloaded. The code below creates correctly the tabs according to the JSON data, it populates the page but - of course - it displays the same data for each page because the content of datas is overwritten by the forEach.

<App>
        <JavaScript>
            var Observable      = require("FuseJS/Observable");
            var datas           = Observable();
            var occurrences     = Observable();

            var json = {
                "category": [
                    [
                        "Music",
                        "Theatre",
                        "Shows"
                    ]
    			],
    			"events": [
        			{
            			"title": "Music. Faucibus dignissim parturient.",
            			"occurrence": "Music"
        			},
        			{
            			"title": "Music. Taciti ante scelerisque consequat.",
            			"occurrence": "Music"
        			},
        			{
            			"title": "Theatre. Condimentum adipiscing leo.",
            			"occurrence": "Theatre"
        			},
        			{
            			"title": "Shows. Ut vestibulum tincidunt consectetur.",
            			"occurrence": "Shows"
        			},
        			{
            			"title": "Shows. Parturient mi urna commodo.",
            			"occurrence": "Shows"            			
        			},
        			{
            			"title": "Shows. Pharetra pretium nisl felis.",
            			"occurrence": "Shows"
        			}
        		]
        	};
   
        module.exports = {
            data:               datas,
            occurrence:         occurrences,
            occurrenceCount:    occurrences.lenght,
        };

 
        // Get 'category' values and add them to 'occurrences'
        json.category.forEach(function(item){
            occurrences.replaceAll(item);
        });

        // for each category (occurrences) get 'events'
        occurrences.forEach(function(entry){

            //console.log(entry);
            json.events.forEach(function(item){
				
                // There's should be a different 'datas' for each category (occurrences)
                // that should be binded below to it's proper tab
                datas.add(item);
           });

        });

        // Debug. Output events
        datas.forEach(function(events) {
            console.log(events.title);
        });

    </JavaScript>

    <ClientPanel>
        <Panel Dock="Top">
            <PageIndicator Navigation="mainNav" Orientation="Horizontal" ItemSpacing="10" Alignment="Left" Margin="5">
                <DockPanel ux:Template="Dot" Color="#CCC" Padding="10,5">
                    <Text Color="#000" Value="{Page Title}"/>
                    <Clicked>
                        <NavigateTo Target="{Page Visual}"/>
                    </Clicked>
                </DockPanel>
            </PageIndicator>
        </Panel>
        
        <Page ux:Class="MyPage" Color="#AAA">
            <ScrollView Margin="0,0,0,0">
                <StackPanel ItemSpacing="6" >
                    <Each Items="{data}">
                        <Text Value="{title}" />
                    </Each>
                </StackPanel>
            </ScrollView>
        </Page>
        
        <PageControl ux:Name="mainNav">
            <Each Items="{occurrence}">
                <MyPage Title="{}" />    
            </Each>
        </PageControl>

	</ClientPanel>
</App>

(The structure of the JSON can be modified if needed as I did the API by myself.)

  1. I don’t know how I could set/create an Observable that could keep the fetched data subdivided by category

  2. Once I have this Observable I don’t know how to dinamically bind it to the UX.

If you can change the JSON structure, that would indeed be the easiest approach in this case. You could, of course, transform it on Fuse side, but that would be a completely unnecessary operation, provided you can supply correctly formatted data at once.

If you want those lists to be populated all at once (as opposed to being loaded as you activate a given page), then you should deliver the JSON formatted so that it represents the exact structure you need:

<App>
    <JavaScript>
        var Observable      = require("FuseJS/Observable");
        var data            = Observable();

        var json = {
            "events": [
                {
                    category: "Music",
                    items: [
                        {"title": "Music. Faucibus dignissim parturient."},
                        {"title": "Music. Taciti ante scelerisque consequat."}
                    ]
                },
                {
                    category: "Theatre",
                    items: [
                        {"title": "Theatre. Condimentum adipiscing leo."}
                    ]
                },
                {
                    category: "Shows",
                    items: [
                        {"title": "Shows. Ut vestibulum tincidunt consectetur."},
                        {"title": "Shows. Parturient mi urna commodo."},
                        {"title": "Shows. Pharetra pretium nisl felis."}
                    ]
                }
            ]
        };

        data.replaceAll(json.events);
   
        module.exports = {
            data: data
        };
    </JavaScript>

    <ClientPanel>
        <Panel Dock="Top">
            <PageIndicator Navigation="mainNav" Orientation="Horizontal" ItemSpacing="10" Alignment="Left" Margin="5">
                <DockPanel ux:Template="Dot" Color="#CCC" Padding="10,5">
                    <Text Color="#000" Value="{Page Title}"/>
                    <Clicked>
                        <NavigateTo Target="{Page Visual}"/>
                    </Clicked>
                </DockPanel>
            </PageIndicator>
        </Panel>
        
        <Page ux:Class="MyPage" Color="#AAA">
            <ScrollView Margin="0,0,0,0">
                <StackPanel ItemSpacing="6" >
                    <Each Items="{items}">
                        <Text Value="{title}" />
                    </Each>
                </StackPanel>
            </ScrollView>
        </Page>
        
        <PageControl ux:Name="mainNav">
            <Each Items="{data}">
                <MyPage Title="{category}" />    
            </Each>
        </PageControl>

    </ClientPanel>
</App>

Thank you very much. Really. Sadly, I would have never work it out by myself…

I might as well post here since I have the same problem with a minor addon: say I want to add an icon or another value to pass to the PageIndicator. How do I accomplish that?

<App>
    <JavaScript>
        var Observable      = require("FuseJS/Observable");
        var data            = Observable();

        var json = {
            "events": [
                {
                    category: "Music",
                    icon: "a",
                    items: [
                        {"title": "Music. Faucibus dignissim parturient."},
                        {"title": "Music. Taciti ante scelerisque consequat."}
                    ]
                },
                {
                    category: "Theatre",
                    icon: "b",
                    items: [
                        {"title": "Theatre. Condimentum adipiscing leo."}
                    ]
                },
                {
                    category: "Shows",
                    icon: "c",
                    items: [
                        {"title": "Shows. Ut vestibulum tincidunt consectetur."},
                        {"title": "Shows. Parturient mi urna commodo."},
                        {"title": "Shows. Pharetra pretium nisl felis."}
                    ]
                }
            ]
        };

        data.replaceAll(json.events);

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

    <ClientPanel>
        <Panel Dock="Top">
            <PageIndicator Navigation="mainNav" Orientation="Horizontal" ItemSpacing="10" Alignment="Left" Margin="5">
                <StackPanel Orientation="Horizontal" ux:Template="Dot" Color="#CCC" Padding="10,5">
	            <Text>[ </Text>
                    <Text Color="#000" Value="{Page Icon}"/>
                    <Text> ] </Text>
                    <Text Color="#000" Value="{Page Title}"/>
                    <Clicked>
                        <NavigateTo Target="{Page Visual}"/>
                    </Clicked>
                </StackPanel>
            </PageIndicator>
        </Panel>

        <Page ux:Class="MyPage" Color="#AAA">
            <string ux:Property="Icon" />
            <ScrollView Margin="0,0,0,0">
                <StackPanel ItemSpacing="6" >
                    <Each Items="{items}">
                        <Text Value="{title}" />
                    </Each>
                </StackPanel>
            </ScrollView>
        </Page>

        <PageControl ux:Name="mainNav">
            <Each Items="{data}">
                <MyPage Title="{category}" Icon="{icon}" />
            </Each>
        </PageControl>

    </ClientPanel>
</App>

@mircea your question is not related to this at all, since you’ve already got the JSON structure right as we can see from the code you posted :slight_smile:

The question you have is actually about how {Page *} bindings work, which is explained in this example and this code-only sample.

Hope this helps! If it doesn’t, please make a new forum post with specific questions.

@uldis
Thanks for the help.

That example was one of the first things I looked at and although at first glance it seemed exactly what I needed, when I tried to adapt it I couldn’t get it ro run. I gave it a shot again today with a clear head and I got it working. The issue was that I was trying to use string for defining a new attribute when I should have used

<ResourceString Key="Label" Value="{name}" />

I must say that the Page * bindings and ResourceString really threw me off, as I felt like they came out of the blue.

I went back to the documentation and there’s not really much on ResourceString or any helpful info on its parent page about when/why to use a Resource.

You are correct on that we don’t have good documentation on {Page *} bindings, and we’re working on that. Which is also the reason why I immediately guided you to the two examples, not docs.

Glad you got it working!