News feed - store last result and show it when app launches

Hi!

i have an app with a login page and a news feed page:

        <LoginPage ux:Template="login" router="router" />
        <HomePage  ux:Template="home"  router="router" />

once the user logins I navigate to the home page and i fetch + draw the results on a scrollview (and that may take like 1 or 2 seconds (even the query is quite fast it takes a bit of time to draw 40 results)

I would like to store the results so if the same person logins again I would show the “stored results” and then query + fetch the new ones. I have tried to store it in a file and it works but it still takes 1 or 2 seconds to draw it.

so:

1.- is there a way of store the results so i don’t have to “paint” them? (facebook style)

2.- should i show just some results and “paint” the other as the scroll goes down ?

3.- how can i execute some code “on app start” ?

Thnx!!

Hi Zaulin, I can probably help out most on point 3 here,

Any top-level JS code is going to get run on startup so for example:

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

        console.log("hi"); // << this line will run at JS startup
    </JavaScript>

Please note that each time your UX live-updates (like when you are editting the UX in preview mode) this is treated kind of like an app restart so that code will run again.

If you want the app to be in some other state when you act then I recommend looking at the docs for Lifecycle.

Does this cover 3 well enough for you?

I think that would do it.

Thnx!

one last question:

on starting i load the last results of the homePage of the user (homePage have an uxHomePageResults = Observable() that cotanins the list of items) so the user can check even having no net (as long as he has loaded it at some point)

but when i navigate to the homePage there is nothing there i guess as homePage is a class and it’s not the same “homePage” where i loaded the info

main.js

var home = require("home");

home.loadStoredInfo();

home.js

var uxHomePageResults = Observable() 

loadStoredInfo(){
    //loads the info that was stored in a text file
    uxHomePageResults.add(...);
}

homePage.ux

<Panel ux:Class="HomePage">
    <Router ux:Dependency="router" />
    <JavaScript File="home.js" />

    <Each Items="{uxHomePageResults}">
    ....

to solve that i have declared the uxHomePageResults on the main.js but i don’t know if there is a good practice to handle that kind of issues

You can use storage to write and read text files. When you fetch your feed, store the JSON to the text file. Next time the app starts, read the text file, and pre-populate your object with data from the JSON.

Example on how to write it:


  storage.write("kb.favorites.v2.txt", JSON.stringify(favorites)).then(function (success)
  {
    if (success) {
        debug_log ('Stored file');
    } else {
        debug_log ('Storing file FAILED');
    }
  });

Example on how to read it:

  storage.read("kb.favorites.v2.txt").then(function (content)
  {
    //debug_log ('inside read favorite file');
    if (content)
    {
      //debug_log(content);
      var f = JSON.parse(content);
      //favorites.clear();
      debug_log ('favorites file read');
      //debug_log (JSON.stringify(f));
      // loop through each favorite and add to existing observable array

    }
  });

actually i am already storing the last results on a .json file and doing what suggested… the first question was about: is is possible to keep the last UX so i don’t have to re-paint (reading from a file) all the items of a list?

I use router.push method to open the new screen on top of the current, when the user returns, the underlying screen is shown as is.

Ish Singh wrote:

You can use storage to write and read text files. When you fetch your feed, store the JSON to the text file. Next time the app starts, read the text file, and pre-populate your object with data from the JSON.

Example on how to write it:


  storage.write("kb.favorites.v2.txt", JSON.stringify(favorites)).then(function (success)
  {
    if (success) {
        debug_log ('Stored file');
    } else {
        debug_log ('Storing file FAILED');
    }
  });

Example on how to read it:

  storage.read("kb.favorites.v2.txt").then(function (content)
  {
    //debug_log ('inside read favorite file');
    if (content)
    {
      //debug_log(content);
      var f = JSON.parse(content);
      //favorites.clear();
      debug_log ('favorites file read');
      //debug_log (JSON.stringify(f));
      // loop through each favorite and add to existing observable array

    }
  });

Is there a specific location where the .txt files are saved. Can’t find on app folder?

Hi…

Where files are stored when using the Storage moudule depends on what platform the code is running on:

  • Android: the internal storage (getFilesDir) will be used - ref: Android storage details
  • iOS: the Documents directory will be used - ref: iOS File System Basics
  • Windows: %LOCALAPPDATA% (usually c:\Users\[username]\AppData\Local)
  • OS X (dotnet, fuse preview): /Users/[username]/.local/share/
  • OS X (cmake): /Users/[username]/Documents/

We’re aware that this is a bit of a mess, and we’re working on a replacement for the Storage module.

Regarding your other question; it would be really helpful if you could provide a complete working example that demonstrates the issue. With a description of expected behavior, just to avoid any confusion. :slight_smile:

ok!!

a couple of comments and an example:

  • I don’t have any problem with the storage of the data (i am using FileOps and it 's working fine enough https://www.fusetools.com/community/forums/show_and_tell/fileops_javascript_module)

  • I want to load and fill the homePage when the app launches ( I will load the last logged user results and clear it if the user changes)

  • I know i can do everything on the “onParameterChanged” of the homePage but the problem is that it takes a bit (maybe 1 second) to “paint” all the results (limited to 20) and that’s why i want to do it “on Launch”

  • The main question is: What should i write on the thingsToDoAtLaunch function to set the value of the home.myHomeValue to “hello world”?

an example:

MainView.ux

<App>
<Router ux:Name="router" />

<JavaScript File="main.js"/>

<DockPanel>
    <StatusBarBackground Background="#595959" Dock="Top"/>
    <iOS.StatusBarConfig Style="Light"/>
    <BottomBarBackground IncludesKeyboard="false" Dock="Bottom"/>

    <Navigator DefaultTemplate="login" >

        <LoginPage ux:Template="login" router="router" />
        <HomePage  ux:Template="home"  router="router" />

    </Navigator>

 </DockPanel>
</App>

main.js

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

thingsToDoAtLaunch();

function thingsToDoAtLaunch() {
    console.log("doing some things");
    //Here i would like to set the value of home.myHomeValue to "hello world"
}

module.exports = {


}

LoginPage.ux

  <Panel ux:Class="LoginPage" Background="#fff">
<Router ux:Dependency="router" />

<JavaScript File="login.js" />

<StackPanel>
    <Button Height="30" Clicked="{loginClick}">
        <Text Value="Login" TextAlignment="Center" Alignment="VerticalCenter" TextColor="#fff"/>
        <Rectangle Layer="Background" CornerRadius="10" Fill="#68C4FB">
            <Stroke Width="1" Brush="#68C4FB"/>
        </Rectangle>
    </Button>

    <Button Height="30" Clicked="{loginClickChangeValue}" Margin="0,20,0,0">
        <Text Value="Login param change" TextAlignment="Center" Alignment="VerticalCenter" TextColor="#fff"/>
        <Rectangle Layer="Background" CornerRadius="10" Fill="#68C4FB">
            <Stroke Width="1" Brush="#68C4FB"/>
        </Rectangle>
    </Button>
</StackPanel>

</Panel>

login.js

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

function loginClick(){
  console.log("login Click");
  router.push("home");
}

function loginClickChangeValue(){
  console.log("login Click --> change value");
  router.push("home", {p: 1});
}

module.exports = {

   //Funciones
loginClick:     loginClick,
loginClickChangeValue: loginClickChangeValue,

}

HomePage.ux

    <Panel ux:Class="HomePage">
<Router ux:Dependency="router" />
<JavaScript File="home.js" />

<DockPanel>
    <Text Value="HOME PAGE" TextColor="#000" Dock="Top" Alignment="Center"/>
    <Text Value="{myHomeValue}" TextColor="#000"/>
</DockPanel>

</Panel>

home.js

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

var myHomeValue = Observable("default value");


this.onParameterChanged(function(param) {    
    myHomeValue.value = "called with a push with parameter";
});


module.exports = {
    myHomeValue: myHomeValue
}

Thanks. I’ll have a look at this later today. :slight_smile:

Hi…

As far as I know there’s no straightforward way to paint a element contained in a <Navigator> tag before router.push() is called. When the code in main.js runs the <HomePage> element has not yet been instantiated.

You could export the myHomeValue observable from main.js and refer to that one, but I don’t think that will fix your problem.

Note that I don’t have a lot of experience with the Navigator myself, so there’s probably others here who can give you a better answer. I’m sure there’s some other way to solve this problem.

1 second sounds like a long time to paint 20 items of something on a page. Can you tell me what each item contain? If you’re able to provide an example demonstrating the actual performance problem we could maybe see if there’s other ways to improve this.

If you don’t want to publish your code on a public forum it’s also possible to upload a zip file to https://www.dropbox.com/request/ZgndLtJQm5eGzG9cicGK (only available to Fuse dev team).

uploaded!

as you can see in the example it takes “0 seconds” since the query fetches the results and those results are added to the Observable list but it takes “a bit” (like one second) till those items are shown on screen (the same happens on the mobile device (maybe a bit faster))

Hi :slight_smile:

I’ve taken a look at your example, and from what I can observe it is the request to the API that takes most time. The timestamp printed just got 1 second resolution, which is easy to get fooled by.

To verify this I removed the HTTP request from the equation, and just hardcoded the JSON returned. This removed the 1 second wait time.

For me the HTTP request takes a little over a second when testing from a browser, but this can oh course vary depending on routing distance to the server.

Hi!

have u tried to just “paint” 2 results for example ? (i mean just observable.add(item) twice)

I found that if i “paint” less results it goes way faster (that’s why i think it takes some time to do so)

Hello again…

Some followup questions:

  • Is the increase linear? And when you say slow, how much time do you mean?
  • The ~1-second delay in your example, do you agree this was due to the REST API being slow, as I mentioned in my previous post?
  • On what platform and device does the problem appear?

hehe… i posted a reply with some video examples :slight_smile: but it seems it was not saved… let me find it …

ok… here we go… :slight_smile:

here you can see 2 examples where the timer starts when the last result is added to the Observable array. Both examples fetch the same amount of results but the “short” one just draw 2 of them

short (2 results drawn):

https://www.youtube.com/watch?v=e_lacxXTDig

long (20 results drawn):

https://www.youtube.com/watch?v=SJG3SF_T-Qg

as you can see it takes much more time in the second example.

answering ur questions:

  • yes… it’s linear… when doing so “drawing” 100 items it takes like 3 seconds

  • I don’t think so as show in the videos (same api and the only difference is the amount of items added to the observable)

  • Testing on local but it happens in iPhone 5 too

Thanks for the videos

On my Windows workstation (in preview) the layout time seems to be ~170ms, but on my macbook I get approximately same result as in your videos.

  • Windows 10: ~170ms
  • MacBook OS X: ~1300ms

I will talk with the layout engine guys and check whether this is expected or not, and get back to you once I know more… :slight_smile:

Hi…

I’ve done a bit more profiling.

From what I’ve observed it looks like the performance is better on iOS for the final build (~150ms), but a bit worse when using preview.

The local fuse preview uses the mono .NET runtime on OS X, which might explain why the performance is so much better on Windows. It could for example be we are very frequently calling some API that’s much slower on mono.

I will create a ticket for this as I agree that the performance is below what should be expected for this use case.