How to divide main code in different js files

Hi,

I want to split the js code of the MainView in different files but i don’t know how to access an Observable list on the second file from the main one:

The mainPager.loadFeeds(); gets called but it only shows the “console.log(”…")" the observable is not shown but it works when called from the page (clicking on the button). How should i do it?

MainView.ux:

<App>
	<JavaScript>

        var Observable = require("FuseJS/Observable");
        var mainPager = require("mainPager.js");

        var uxbLogged = Observable(false);

        function onLoginClick(){
            uxbLogged.value = true;
            mainPager.loadFeeds();
        }

        module.exports = {
            onLoginClick: onLoginClick,
            uxbLogged: uxbLogged
        }
	</JavaScript>

    
    <PageControl ux:Name="LogginPager">
        <Page ux:Name="LoggedOut">
            <StackPanel Background="#fff">
                <Text Value="Loggedout page"/>
                <Button Text="Login!" Background="#f0f" Margin="20">
                    <Clicked Handler="{onLoginClick}"/>
               </Button>   
            </StackPanel>
        </Page>

        <Page ux:Name="LoggedIn">
            <ux:Include File="MainPager.ux" />
        </Page>

        <WhileTrue Value="{uxbLogged}">
            <Set LogginPager.Active="LoggedIn"/>
            <Callback Handler="{loadFeeds}"/>
        </WhileTrue>
        <WhileFalse Value="{uxbLogged}">
            <Set LogginPager.Active="LoggedOut"/>
        </WhileFalse>
    </PageControl>



</App>

MainPager.ux:

<DockPanel>
    <JavaScript File="mainPager.js" />

    <PageControl Active="{pageControlActivePage}">
        <Page ux:Name="newsFeedPage">

            <Router ux:Name="routerNews" BackButtonAction="None"/>
            <Navigator>
                <Page Name="newsFeedsMainPage">
                    <StackPanel Background="#f0f" ux:Name="main">
                        <Text Value="This is the news feeds page"/>
                        
                        <Button Text="Load feeds" Background="#00f" Margin="20">
                            <Clicked Handler="{loadFeeds}"/>
                        </Button>

                        <ScrollView>
                            <StackPanel>                    
                                <Each Items="{uxFeedsPageResults}">
                                    <StackPanel Margin="5" Background="#EEE">
                                        <Text Value="{user}"/>
                                        <Text Value="{data}"/>
                                        <Text Value="click here for more info"/>
                                        <Clicked Handler="{onFeedClicked}"/>
                                    </StackPanel>
                                </Each>
                            </StackPanel>
                        </ScrollView>
                    </StackPanel>
                </Page>

                <ProfilePage ux:Template="profilePage" router="routerNews" />
                <DataPage ux:Template="dataPage" router="routerNews" />
            </Navigator>

        </Page>

        <Page ux:Name="friendsPage">
            <Router ux:Name="routerFriends" BackButtonAction="None"/>
            <Navigator>
                <Page Name="aaa">
                    <StackPanel Background="#0ff">
                        <Text Value="Page2"/>
                        <Button Text="Go to profile" Background="#fff" Margin="20">
                            <Clicked Handler="{page2Click}"/>
                        </Button>
                    </StackPanel>
                </Page>

                <ProfilePage ux:Template="profilePage" router="routerFriends" />
                <DataPage ux:Template="dataPage" router="routerFriends" />
            </Navigator>
        </Page>
    </PageControl>

    <Panel Dock="Bottom" Height="100">
        <Grid ColumnCount="2">
            <Rectangle Background="#000">
                <Stroke Width="2" Color="#fff"/>
                <Text Value="Feeds" TextColor="#fff" Alignment="VerticalCenter" TextAlignment="Center"/>
                <Clicked>
                    <Callback Handler="{tab1Clicked}"/>
                </Clicked>
            </Rectangle>
            <Rectangle Background="#000">
                <Stroke Width="2" Color="#fff"/>
                <Text Value="Profiles" TextColor="#fff" Alignment="VerticalCenter" TextAlignment="Center"/>
                <Clicked>
                    <Callback Handler="{tab2Clicked}"/>
                </Clicked>
            </Rectangle>
        </Grid>
    </Panel>
</DockPanel>

mainPager.js:

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

var pageControlActivePage = Observable("newsFeedPage");
var uxFeedsPageResults = Observable();

function onFeedClicked(sender){
    var textToShow = sender.data.user + " " + sender.data.data;
    routerNews.push("dataPage", {text: textToShow});
}

function loadFeeds(){
    console.log("loading feeds");
    
    uxFeedsPageResults.clear();
    uxFeedsPageResults.add(
        {user: "user1", 
        data: "data1"});
    uxFeedsPageResults.add(
        {user: "user2", 
        data: "data2"});
    uxFeedsPageResults.add(
        {user: "user1", 
        data: "data3"});
}

function tab1Clicked(){
    pageControlActivePage.value = "newsFeedPage";
}

function tab2Clicked(){
    pageControlActivePage.value = "friendsPage";
}

module.exports = {
    tab1Clicked: tab1Clicked,
    tab2Clicked: tab2Clicked,
    pageControlActivePage: pageControlActivePage,

    onFeedClicked: onFeedClicked,
    uxFeedsPageResults: uxFeedsPageResults,
    loadFeeds: loadFeeds
}

Hi!

Instead of keeping code in ´´ tags, build your code around stand alone JS modules.

You can move code to stand-alone file.js files, include them in the :Bundle in your .unoproj and then simply require("file") them wherever needed. This way you can share any objects/data/observables between as many pages as you like

Hi!

done (and working) it was strange that if i included the files with

    <JavaScript File="myfile.js" />

i could call the functions but Observables where not shown.

thnx!

one final question:

then how do i access router from that file ? or should i keep the

    <JavaScript File="myfile.js" />

to use it when the router is needed? (that would be weird as i would have all the functionality of the page split in 2 js files)

Hi!

To access a Router instance in various parts of your app, you should pass it to your components via ux:Dependency. Our Navigation and Routing tutorial chapter goes over this specifically, and the previous chapter is all about splitting up your app into different components and routing data between them.

Hi!

did you notice that i don’t want to use it in a template? (the links show how to do it when working with templates)

        <Navigator>
            <Page Name="newsFeedsMainPage">
            <Page/>
            <ProfilePage ux:Template="profilePage" router="routerNews" />

where would you place the ux:Dependency so on?

I need:

1.- be able to modify the content of the “newsFeedsMainPage” from the MainView.ux so:

            <Page Name="newsFeedsMainPage">
                      <JavaScript File="myCode.js" />
            <Page/>

would not work as then the Observables would not be available from MainView.ux (that was my first question and i was told to move the .js somewhere else)

2.- I want to be able to call the router from that “external” .js so: how do i use the “ux:Dependency” ?

            <Page Name="newsFeedsMainPage" router="routerNews">
            <Page/>

would not work

First of all, why would you not want to use a template? I don’t really see why you wouldn’t want to do so. In either case, ux:Dependency will work regardless of whether or not you’re using a template. Templates are just a mechanism to lazily create the object instance. Perhaps the thing you’re trying to avoid is a custom component, and not a template? Even if that’s the case, I still have a hard time seeing why you would want to avoid one (and you need to use a custom component with ux:Dependency).

As for splitting out your JS so both your MainView and your other page can see your Observables, the best way to do that is to create a JS module that the JS code for your views require. This is why I linked the tutorial; the Context module covered there is the solution here.

I want some things to be loaded on that page BEFORE the login so i need the page to be a non-template.

From documentation (Since 0.29):

"
Non-template pages can also be used. The Name of the page will be used to match the path:

These pages always just have the one instance, will always be reused, and will never be removed. Otherwise they function the same as the template pages.

Here are some general rules that will you help decide whether you want to use a template or non-template page:

If you need transitions between pages with the same path, but different parameter, then use a template.
If you have pages that impact performance even when inactive, or for other reasons should be removed when unused, then use a template.
If you have a page that should always exist to preserve state, or is very frequently navigated to, use a non-template.
"

So that’s why i want a non-template page :slight_smile:

When u mean: “a custom component” u mean a ux:Class with the dependency? like:

<Page ux:Class="NewsFeedMainPage">
    <Router ux:Dependency="router" />
    <JavaScript File="newsFeedMainPage.js" />

and:

        <Router ux:Name="routerNews" BackButtonAction="None"/>
        <Navigator DefaultPath="newsFeedsMainPage">
            
            <NewsFeedMainPage Name="newsFeedsMainPage" router="routerNews"/>
            <ProfilePage ux:Template="profilePage" router="routerNews" />

?

As you suggested I solved it moving just the observable on to another file.

obs.js:

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

var uxFeedsPageResults = Observable();

module.exports = {
    uxFeedsPageResults: uxFeedsPageResults,
}