app-router integration
My app component contains my UniFlow dispatchers. It also contains my <app-location> and some of my <app-route> components. In Where to call server API, google/uniflow-polymer#1, we determined that we could emit a save action from a page such as a Profile Edit page. Some dispatcher would take care of calling the back end server API to save the data and emit its own action for success or failure. Another dispatcher (or the same) would receive the success action and handle routing.
How do you suggest setting that up? Would you pass the route into the dispatcher and put an <app-route> component in the dispatcher to be manipulated?
<my-app-dispatcher state="{{state}}" route="{{route}}"></my-app-dispatcher>
Then in <my-app-dispatcher> have a <app-route route="{{route}}"> in the template section so that it can be manipulated in the action methods that need to handle routing?
(I'll try this myself but) Can an observer be used to watch a specific portion of the state tree? For my application, my main app needs to know when the user is logged in or not and route to either the login screen or, depending on the logged in user's roles, a specific page. Can I use a simple
observers: [
'onLoggedIn(state.auth.user.token)'
]
Is that the best method to listen to different branches of the state tree? In a lot of cases the state-path will be a section of the tree specific to the page but the page will still need access to other sections of the tree such as the current user's information.
A few quick tests of using observers show that you can use them to either monitor the entire tree onStateChanged(state.*) or a portion of the tree, onStateChanged(state.auth.*), or a specific value in the tree, onStateChanged(state.auth.user)` just like Polymer documentation says you can.
So that does handle the checking for a logged in user. Now to figure out routing.
I have not used app-route in production app, so might not know all the details about it. However I don't see a reason to put
This does work. I had to do two things to make it work, maybe because of the order things get created, not sure?
First I updated <app-location id="location" route="{{state.route}}">. That alone does not do it. state.route does not get updated. I also had to set state.route to the app-location route object like so:
ready: function() {
this.set('state', {
route: this.$.location.route
});
},
I tried setting state.route to {} in ready but that doesn't work.
I'm not positive I'll stick with this though.
That makes sense. <app-location> uses two-way binding for route, which makes it a bit difficult to use in uniflow pattern (in which elements either listen to state changes or mutate state, but never both). Do you have your app on GitHub somewhere for me to take a look and see if I can suggest something for your specific case?
Also using chained routers (passing tail to route of component) we are able to only manage the portion of the URL we are displaying and don't need to worry about where it was called from in the URL chain making it easier to use the same component that has routing from multiple locations in the app.
The app is closed source so I don't have something to show you. I'm going to test not using state in app-router and also not passing the routing information to the dispatchers. That won't work either since the routers need to be chained.
Instead, I'm going to use the emitAction to save data and then use the standard fire method from the action to let my components know to change route if needed. In the original SAVE_USER example that would mean the component's save method would simply validate the form and emit a SAVE_USER message with the model. It (or the parent of it) would listen for a standard 'user-saved' message and handle routing.
I've just done an UniFlow version of the Polymer Starter Kit, where I try to do the routing operations using actions. All feedback is welcome...
Looks good. Where I'd want to see more is a link in view1 to view2, a button in view2 to view3, and also a use of the BACK action. I use a type of BACK action in my app when someone hits cancel on some of my pages. Nice that you don't need to worry where exactly they came from when they hit Cancel, especially when that page is called from multiple locations.
The other issue I ran into was nested app-route components. So if view1 had an iron-pages on it and used a route that was passed in from the app's app-route tail property to determine which page to show. How can that be handled with UniFlow cleanly. I'm sure it can, just need something like that level of sophistication in the starter app so people don't hit a roadblock on day 2. So how would /view1/page1 and /view1/page2 get handled.
My current non UniFlow solution differs by returning a promise for its emitAction equivalent. That allows me to do some routing right from the component. Emit save, wait for success, then fire a standard event like this.fire('save-clicked') for higher components. I tried to fire events from my action dispatcher but since it is at the root of the application, the event didn't go anywhere. Events bubble up, not down. I had to pass in the calling element which seemed dirty. With a promise in UniFlow you could call the emitAction CHANGE_PAGE event from the component rather than from the action dispatcher. Of course the initial emitAction to SAVE could include an onSuccessPage value that could be passed to CHANGE_PAGE on success. So many ways to do it :-)
@LostInBrittany Thanks a lot for your work! I made some comments here: code review, but overall looks great as a starting point. I would be happy to contribute by adding more non-trivial scenarios on how UniFlow can be used, but the problem is as usual: finding time to do that. So can't promise anything at this time, but will keep this in mind in case I'll have some spare cycles.
I have also had a go at Polymer 2.0 + Uniflow + app-location, app-route integration. I wanted changing the URL in the address bar, links to work also and to have some state change with the page (in the real app it would be a rest call to pull back data for the page).
It sort of works but I've come across an issue, it seems that when the app loads (first time, and when the URL is changed) the emit of the page event is firing before the action-dispatcher is ready to receive the event although the code works fine when triggered in other situations without a full app reload. Is there a way to prevent emits of actions until the dispatcher is ready?
Could be my understanding of either polymer or uniflow though, but I'd appreciate some help as I can't see how to fix it.
I did look at what @LostInBrittany had done but I couldn't see how it would do what I wanted.
Repo here - https://github.com/RobMaskell/PolymerSandbox