01-08-2018 15:39 - edited 01-08-2018 16:05
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post

01-08-2018 15:39 - edited 01-08-2018 16:05
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post
- Who Voted for this post?
If you wanted to have the multi-screen application boilerplate having SVG split to several .gui files, you now have it. Updated Ionic Views UI micro-framework.
Same for jQuery-style $( '#id1 #id2' ) selectors.
Same for hierarchical subviews. View now comes with an energy-saving bonus: render is automatically suppressed when the screen is off (and app render is forced when the screen goes on). So, don't bother with that optimization. It just works.
Special thanks to @kmpm who helped to test and debug the thingy. Btw its size is about 100 lines of code, don't be afraid to look inside.
Don't forget to put a star if you like it.
01-09-2018 06:30
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post

SunsetRunner
01-09-2018 06:30
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post
Nice multiscreen boilerplate.
Now I need to work out where to place the code to periodically read sensor data even if the screen is off...
Quite happy to share the project once it is in a stable state ....

01-09-2018 06:40
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post

01-09-2018 06:40
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post
You do it in the separate class, which should be instantiated in application’s class onMount().

01-09-2018 06:44 - edited 01-09-2018 08:01
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post

01-09-2018 06:44 - edited 01-09-2018 08:01
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post
Look how it’s done in Screen1. It subscribes to the clock tick, and the handler is called even when the screen is off. View.render(), however, is no-op in this case and view.onRender() won't be called.
You should not do any data processing in onRender() method itself. Just update the UI here. In general, the view pattern resembles BackboneJS View and should be treated accordingly.

01-09-2018 07:57
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post

SunsetRunner
01-09-2018 07:57
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post
@gapertonthanks for your replies:
I have added sensorReadings.js in app:
export class sensorClass { myVar=0; myTimer=0; start() { this.myTimer=setInterval(this.increment(),1000); console.log("Start"); } increment() { this.myVar++; console.log(this.myVar); } stop() { clearInterval(this.myTimer); console.log("Stop"); } }
and have the following in index.js
import document from "document"; import { Application } from './view' import { Screen1 } from './screen1' import { Screen2 } from './screen2' import { sensorClass } from './sensorReader' class MultiScreenApp extends Application { screen1 = new Screen1(); screen2 = new Screen2(); mySensorReadings = new sensorClass(); // Called once on application's start... onMount(){ // Set initial screen. // Same as Application.switchTo( 'screen1' ), which might be used to switch screen from anywhere. this.screen = this.screen2; this.mySensorReadings.start(); document.onkeypress = this.onKeyPress; } onUnmount() { this.mySensorReadings.stop(); } // Event handler, must be pinned down to the class to preserve `this`. onKeyPress = ({ key }) => { if( key === 'down' ){ // Just switch between two screens we have. Application.switchTo( this.screen === this.screen1 ? 'screen2' : 'screen1' ); } } } // Create and start the application. MultiScreenApp.start();
As I am intending to log data on a periodic basis, I am assuming the best place to do this is from the main application, so that portions from the same base of data can be used across different screens.
So build the class that will "kick off" the sensor event subscriptions, and record the data within the class. Run a secondary timer to bring together the readings from the various sensors, make calculations (distance from GPS, average HR & cadence i.e. all data processing) and log to a file for later analysis (once messaging is reliable). Sensor events can be unsubscribed in unmount if not already stopped.
In the above code, I do indeed get the console log that the start function has fired. And that is it. No periodic messages. No message prior onunmount. What have I done wrong (or broken)?
Is my thought process broken??

01-09-2018 08:06
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post

01-09-2018 08:06
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post
- Who Voted for this post?
> Is my thought process broken??
Nah. Just the small bug in your code. In this line:
this.myTimer=setInterval(this.increment(),1000);
It should be:
this.myTimer=setInterval( () => this.increment(), 1000 );
01-09-2018 08:16
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post

01-09-2018 08:16
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post
- Who Voted for this post?
Also, if your intention is to use the single instance of the SensorClass in all the views, it might be better to export it right from the module. Like this:
class SensorClass {
constructor(){
// ...
this.start();
}
// ... }
export default new SensorClass();
Then, it can be imported from anywhere like this.
import sensor from './sensor'
The different question is how you will update our UI in case of changes. The simplest way I would recommend to start with is having the single onChange callback in your sensor class and calling the Application.render. Thus, whatever screen is active it will be updated on reading changes, and you don't need to manage multiple subscribers in sensor class.
onMount(){ this.screen = this.screen2;
document.onkeypress = this.onKeyPress;
sensor.onChange = () => this.render();
}
01-10-2018 07:52
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post

SunsetRunner
01-10-2018 07:52
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post
- Who Voted for this post?
Understood. And works like a charm.
I will go ahead and re-build my app using your boilerplate and upload to github. Expect an incoming post by the close of the weekend. 🙂
01-10-2018 14:58
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post

SunsetRunner
01-10-2018 14:58
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post
Hello again @gaperton:
I am now just trying to work out how to reference an Application method from a screen class.
I have created an "Are you sure you want to exit?" screen, which of course switches into place when required. I have yes and no buttons.
Whilst I can use an me.exit() from within the exit screen, I don't believe that is the correct place, and should reside at the Application class level.
I did try to ensure that the onUnmount method fires by putting a console.log in place - but it didn't produce any output. Could you double check the onUnmount method does function for you?
Thanks
Rob

01-10-2018 17:38 - edited 01-10-2018 17:46
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post

01-10-2018 17:38 - edited 01-10-2018 17:46
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post
- Who Voted for this post?
> I am now just trying to work out how to reference an Application method from a screen class.
import { Application } from './view'
...
Application.instance.anyMethod(); // Bingo!
// To switch the screen from anywere there's the dedicated static:
Application.switchTo( 'nameOfTheAppInstanceMemberHoldingView' );
Everything is taken care of ;).
01-10-2018 17:41 - edited 01-10-2018 17:48
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post

01-10-2018 17:41 - edited 01-10-2018 17:48
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post
- Who Voted for this post?
> I did try to ensure that the onUnmount method fires by putting a console.log in place - but it didn't produce any output. Could you double check the onUnmount method does function for you?
At the time it never works for an Application instance itself, but it should work for the application's screen which is being replaced with another one as well as for any of its subviews.
Probably, it's a good idea to add Application.exit() method which would unmount the screen and call its own onUnmount() hook.
01-14-2018 11:34 - edited 01-14-2018 11:35
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post

SunsetRunner
01-14-2018 11:34 - edited 01-14-2018 11:35
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post
- Who Voted for this post?
Just uploaded to github a far from finished application.
Quite a bit of finessing to do, and all of the styling.
It does give a start to using the Ionic Views template. Hopefully it will help a few people. It may even give the opportunity of the more seasoned developers to contribute/advise if so wished.
https://github.com/non-runner-rob/runmaster
RunMaster is a personal only project, so I won't be releasing it. Got lots planned for it moving forward.
01-14-2018 14:41
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post

01-14-2018 14:41
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post
@SunsetRunner Somehow you uploaded the result of transpiration. Check your app folder, there’s just a single index.js file.
Try “Export” option in FitBit studio.

01-14-2018 23:20
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post

SunsetRunner
01-14-2018 23:20
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post
- Who Voted for this post?
@gaperton Fixed
Not sure what I did (not used GitHub before)
The correct files are now uploaded. (Note to self: Check and Double check what you are uploading).
01-15-2018 21:09
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post

01-15-2018 21:09
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post
Small note regarding your views code. Let's take this as an example.
https://github.com/non-runner-rob/runmaster/blob/master/app/screen-entry.js
Here it would be good to do either of two things:
1) Merge view and element group together. I.e. to cache elements in the view, and update them directly in onRender(). When you have just one element group it means you don't really need it.
2) Split your elements group into several logical groups. Like this:
class Times {
duration = $ ( '#duration' );
startTime = $ ( '#startTime' );
endTime = $ ( '#endTime' );
currentTime = $ ( '#currentTime' );
// UI update method(s). Can have any name, it's just the pattern.
// Element groups have no lifecycle hooks, thus all the data required for UI update
// must be passed as arguments.
render({ pduration, pstartTime, pendTime, pcurrentTime }){
this.duration.text = parseInt(pduration/1000);
this.startTime.text = pstartTime;
this.endTime.text = pendTime;
this.currentTime.text = pcurrentTime;
}
}
Note that I grouped arguments in render to an object. See { .. } brackets? So, you will render it like this:
onRender(){ this.times.render( runMaster ){
// render other elements groups... }
Which is much better, isn't it? That's how they meant to be used. Logically group UI elements so render code won't look so messy.

01-16-2018 03:48
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post

SunsetRunner
01-16-2018 03:48
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post
As said above, lots of finessing to do. Appreciate you input.
Only threw in all the stats onto one screen to confirm they are as they should be. Will then split them out accordingly into specific screen displays. Will also provide methods in RunMaster to provide formatted data rather than at each point the data is consumed.
Still learning this new fangled class thingamybobwhatsit
Ionic Views does make things so much more straightforward for me.

01-17-2018 11:07 - edited 01-17-2018 11:10
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post

01-17-2018 11:07 - edited 01-17-2018 11:10
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post
- Who Voted for this post?
> Will also provide methods in RunMaster to provide formatted data rather than at each point the data is consumed.
This part is questionable. Not that it would break your app or anything like that, it's rather about the general UI apps architecture. I will explain.
An overall point of good architecture is to control the complexity. The "complex" can be defined as "big and messy", so what you do to fight the complexity is splitting something "big" to the set of loosely connected smaller parts.
The first step is to use the "layers" pattern. There are at least two "layers" naturally present in your app - "view layer", and "data layer". The data layer (runMaster) is on the bottom, which means that it should have no knowledge of the upper "view" layer. It means that the data layer should not know about formatting. Formatting is dependent on data representation in the UI, which by definition is the "view" layer job.
Why it's helpful? Imagine that someone needs to make a change to look and feel of your app. If your data layer is clearly separated, such a person can safely ignore it concentrating on the view layer only and making the change which is local to the single view. That's the point - he doesn't need to understand your system as a whole to make his change, he can concentrate on the small isolated part. The same thing is right for you as well, you can forget about irrelevant parts of your app when you're working on some particular task.
Then, if your views become big/messy, you split them down into subviews/element groups as well. That's how it works.
01-19-2018 01:56
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post

SunsetRunner
01-19-2018 01:56
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post
The more I work with Ionic Views, the more I like it.
As I add more screens into RunMaster, the more difference it makes.
One of the things I am currently trying to work out, is how to have a common gauge across a selected number of data views.
Let me explain the need:
Creating a running app, one of the things important to me is being able to glance how well I am doing against my pace and average heart rate targets, regardless of what unit of metric I have onscreen at that time.
Rather than have that gauge in each of the views, I want to share it so one common design and code base so to speak.
Whilst I can put a visible design element with id into the index.gui, I am having difficulty referencing it. So at this stage unsure if a) it is wise to follow this approach b) if there is a better way.

01-19-2018 09:01 - edited 01-19-2018 09:04
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post

01-19-2018 09:01 - edited 01-19-2018 09:04
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post
- Who Voted for this post?
> Rather than have that gauge in each of the views, I want to share it so one common design and code base so to speak.
If this widget is positioned on the same place in every screen, an easiest way of doing it is:
1) Include its GUI at the root level once.
2) Define the widget's logic as the separate View.
3) Insert an instance of this View to every screen referencing it. ( myWidget = new MyWidgetView() )
3) In you screen's onMount(), do this.insert( this.myWidget ).
That's it. If the position is different, you'll need to use Template Symbols.
10-03-2018 01:06
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post

10-03-2018 01:06
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post
When implementing it I got the following situations, do you have any idea how you would handle these cases?
- rendering animating components, for instance a spinner. I moved it to render, but now it restarts every time render is called, even when the loading state does not change.
- back button in views (to go to previous screen)
- using combo buttons in screens
- passing information to new view on switchTo

