Mimicking the Facebook app's infinite stack in Ember.js - facebook

Ember routing works nicely when working with strict linear paths of resources. However, it's becoming more prevalent in mobile design for apps — such as the Facebook app — to use infinite stacks of multiple interconnected resources:
User starts in the feed.
Presses on a link to a user profile.
Navigates to user's list of friends.
Visits a new user profile.
Goes to any other types of resources such as posts, groups etc.
THEN can navigate all the way back with each page state persisted.
We start off in a known resource - let's say it's Facebook's news feed. In Ember, we'd define that route as:
this.route('feed');
But from there, we'd like to be able to visit any combination of our resources - whilst still maintaining the state of each route. The temptation is to solve the problem through some funky route solution, such as using catch-all route definitions:
{ path: '*' }
But that'd take some heavy path management as discussed here (or perhaps there's some method of utilising Tilde's router.js URL generation?!). But as per the illustrated example above, it would leave us with huge goddamn route paths:
/feed/users/:user_id/friends/users/:user_id/another_resource/:another_resource_id
Not that that's a problem in a mobile app, but I'm not sure if it's the optimal way of achieving this.
So that leads me to consider whether there's some method of dynamically creating outlets as stacks get deeper (akin to modals) - or whether the only way to achieve state persistence is using an app level object, Ember data or an Ember service to track/persist history & state.
Anyway, tl;dr, I'm not desperately needing this functionality - just interested if anyone has a smart insight into how achieve this ...umm ... infinite interconnected nested resource stack thingy.

The answer does not lie in nesting routes in an attempt to prevent them from being torn down.
Instead the answer lies in state management.
Browser history can be used to manage URLs and bound to the back buttons on each page in our stack. However, restoring the exact state of the page (including scroll position, especially when models may be lazy loaded) requires some additional design.
The easiest method of doing it is using the ember-state-services addon.
In particular, this video by Travis Hoover from Oct '15 was really helpful. It explains how ember-state-services creates 'buckets' for different model instances.
So, when navigating through our Facebook stack, the state of each page can easily be stored & restored even if we visit pages which reference the same route/controller. In our example, it helps with preserving the state of the two user profiles we navigate to (user/:user_id).
So, for storing each user profile pages' scroll positions, get the scroll offset from your scrolling div/component and use ember-state-services as so:
// app/controllers/feed
scrollPos: stateFor('scrollPos', 'model')
// app/routes/feed
saveScrollPos: Ember.on('deactivate', () =>
this.set('scrollPos', scrollValue);
));
It'll store your last scroll positions on users/1 AND users/2 separately because state is bound to the particular user models.
The only gotcha I can foresee is if the user was to visit the exact same route multiple times in one stack, but there's not many use cases where that would be a problem.

Related

How to load all pages at startup?

With the Ionic 4 framework and using the PWA.
I would like all the pages, the whole project is cached as soon as the first page is loaded.
In fact, I would like the user to log in once and then offline to access all pages.
Because currently, only the first page is displayed ..
You are talking about "multiple pages" in a sense that is implying that your implementation does not use the App Shell model.
Probably, you need to do the following things:
Implement the App Shell
Implement navigation between the different content pages of your app
Implement the static content pages (I assume they are static, since you want to primarily use them offline)
Have the service worker cache the whole bunch.
All the content is now cached on first launch. Dynamic content fetched from the server would of course still require an internet connection.

What's the accepted pattern for global, updatable data?

I've gone through several tutorials on Flutter and I find that they cover basics just fine but there are some nagging aspects of good design and good architecture that are consistently missing. I'm writing my first actual (not toy) application in Flutter and find myself running into these missing points.
Global data. Once a person installs the application and tries to use it, I ask them to log in / create an account, since this is an application specifically for managing groups of people. I'm using Firebase on the back end, and the package to do authentication winds up returning Future<FirebaseUser> from everything. So, yes, when it comes to building a Widget that uses the user's data, I can use a FutureBuilder. That said, it seems weird to have to keep typing boilerplate FutureBuilder code to dereference the user every place I want to use the user's ID to look up their data (what groups are they part of, what actions do they have pending, etc.). I really feel like there ought to be a way to invoke the future, get the actual user object, and then store it somewhere so that anything that wants a user ID for a query can just go get it. What's the right solution? I can't believe I'm the only person who has this problem.
Updatable data. I've got a page where I list the groups the current user is a member of. The user, though, can create a new group, join an existing group, or leave a group. When they do that, I need to redraw the page. The list of groups comes from running a Firebase query, so performing an action (join, leave, etc.) should signal the app to redraw the page, which will have the side effect of re-running the query. Conceivably, one might make the page dependent (how?) on the query results and have it redraw whenever they update, and instead have some widget somewhere that keeps track of the query. There's another answer here that hints that this might be the right way to go, but that's really concerned with relatively invariant data (locale doesn't change all that often for a single user). So, again, I can't believe I'm the only one who does this sort of thing. What's the best practice in this case?

What is better: one large REST API call or many small for a Cordova/Backbone app?

This is my first Cordova/Backbone application.
I have grasped the whole deal with Models, Views, etc. somewhat, and now I have gotten to actually making proper view structure for my app.
It is a user centered app, which means that views are dynamic depending on who the user is and their status in the app.
Could you please help me to understand what is a better choice: making one (large-ish) api call to the server to get the data for all user-related app views (that would get all user info, various menus for the current user etc) and put them in one User model or make several smaller api calls that each get a fragment of the information (let's say, profile information, newsfeed information and options for two menus, so 4 ajax calls total) and keep the models separate? All the relevant views (UserProfile, SideMenu, UserProfileMenu and ActivityFeed) are rendered on user login. Some of them are available for user at all times (SideBar menu for example), some get switched out as user navigates elsewhere.
I design the server-side API myself, so I can freely choose what data is returned and when.
"it depends". If you need all the info (from 4 ajax calls) from start, it would be better to create one big api call, because callig server 4 times will last longer than one big call - 4x server ping time. you could use the big call on app start and still create the 4smaller ones to refresh data when needed.

How do I see the aggregates of my published "news.reads" actions?

I have a Facebook application that wants to publish document reads to a user's OpenGraph.
Since read is a reserved, built-in action, my objects have to have the type article. The publishing of reads to the user's graph works fine and the last read is also shown on the user's timeline.
Additionally, I have set up some aggregators that would show the last 5 reads, the most popular authors etc. The problem is that I can not find those aggregators anywhere in my timeline/profile or in the App section of my user.
Is it not possible to control/show the aggregators for built-in actions and objects?
I have a feeling it should be, since I can set them up and (for example) Spotifiy also uses the built-in music.song objects, as shown below - this is basically, what I also want.
All I am seeing on my app's timeline section, though, is this:
I believe you are not in control of when facebook displays your aggregations as you have defined them in your open graph settings, since facebook uses the so called 'GraphRank' to determine whether to show your aggregation or not. The calculation goes like this:
GraphRank = affinity * weight * interactions * time
affinity (score): this is the relationship between the viewing user and the creator of the action.
weight: if two users interact frequently with each other, the respective actions in the open graph are rated higher than for users who do not have the same interest and are not in close contact on Facebook.
interactions: how often does the user interact with the application and how do friends react to the activities in the social channels (if nobody clicks on the published actions it's bad for the GraphRank).
time: if an app is used irregularly or only once, actions will receive less attention in the long run and will be presented less prominently on the timeline.
See this article: http://www.insidefacebook.com/2011/12/27/edgerank-and-graph-rank-defined/
This is not the perfect answer to the actual question but I was able to solve the problem nevertheless. In case someone else is in the same spot, you might profit from my learnings:
The application I'm building wants to push read actions to a user's OpenGraph. My aggregation problem was that my reads from the built-in news.reads action did not get aggregated. To this day, I do not know why not.
Instead, I managed to create my own read action. It is not connected to the built-in one and exists in my own namespace.
This action can now be connected to my own objects as well and is not bound to the article object – as is the built-in one.
Having my own actions and objects, it was a breeze to follow the instructions for aggregations and create as many aggregations as I like. They also actually show up in my test users' profiles. Yeah.

Connectedness & HATEOAS

It is said that in a well defined RESTful system, the clients only need to know the root URI or few well known URIs and the client shall discover all other links through these initial URIs. I do understand the benefits (decoupled clients) from this approach but the downside for me is that the client needs to discover the links each time it tries access something i.e given the following hierarchy of resources:
/collection1
collection1
|-sub1
|-sub1sub1
|-sub1sub1sub1
|-sub1sub1sub1sub1
|-sub1sub2
|-sub2
|-sub2sub1
|-sub2sub2
|-sub3
|-sub3sub1
|-sub3sub2
If we follow the "Client only need to know the root URI" approach, then a client shall only be aware of the root URI i.e. /collection1 above and the rest of URIs should be discovered by the clients through hypermedia links. I find this cumbersome because each time a client needs to do a GET, say on sub1sub1sub1sub1, should the client first do a GET on /collection1 and the follow link defined in the returned representation and then do several more GETs on sub resources to reach the desired resource? or is my understanding about connectedness completely wrong?
Best regards,
Suresh
You will run into this mismatch when you try and build a REST api that does not match the flow of the user agent that is consuming the API.
Consider when you run a client application, the user is always presented with some initial screen. If you match the content and options on this screen with the root representation then the available links and desired transitions will match nicely. As the user selects options on the screen, you can transition to other representations and the client UI should be updated to reflect the new representation.
If you try and model your REST API as some kind of linked data repository and your client UI as an independent set of transitions then you will find HATEOAS quite painful.
Yes, it's right that the client application should traverse the links, but once it's discovered a resource, there's nothing wrong with keeping a reference to that resource and using it for a longer time than one request. If your client has the possibility of remembering things permanently, it can do so.
consider how a web browser keeps its bookmarks. You probably have maybe ten or a hundred bookmarks in the browser, and you probably found some of these deep in a hierarchy of pages, but the browser dutifully remembers them without requiring remembering the path it took to find them.
A more rich client application could remember the URI of sub1sub1sub1sub1 and reuse it if it still works. It's likely that it still represents the same thing (it ought to). If it no longer exists or fails for any other client reason (4xx) you could retrace your steps to see if you can find a suitable replacement.
And of course what Darrel Miller said :-)
I don't think that that's the strict requirement. From how I understand it, it is legal for a client to access resources directly and start from there. The important thing is that you do not do this for state transitions, i.e. do not automatically proceed with /foo2 after operating on /foo1 and so forth. Retrieving /products/1234 initially to edit it seems perfectly fine. The server could always return, say, a redirect to /shop/products/1234 to remain backwards compatible (which is desirable for search engines, bookmarks and external links as well).