Skip to content

Question for AngularJS Core Team #7

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
ProLoser opened this issue Jan 25, 2013 · 5 comments
Closed

Question for AngularJS Core Team #7

ProLoser opened this issue Jan 25, 2013 · 5 comments
Labels

Comments

@ProLoser
Copy link
Member

We are initially planning on building a third-party solution, but we want to design it with the intention of eventually becoming a PR that you guys would look forward to merging into the core. I'd appreciate your input so that we can make this as mergable as possible.

  1. What are major concerns / requirements you guys have for nested routes?
  2. If you were to accept a PR or tackle the routing problem, would you keep backwards-compatibility or just focus on unrestricted changes? (Lets say you put the legacy router into an optional module like ngResource)
  3. There have been several approaches to handling nested routing. Do any of these sound like solutions you were looking at?
    1. Create a nested definition object (Angular.js+)
    2. State-based routing (Ember.js)
    3. Defining route decorators (Lithium PHP)
@IgorMinar
Copy link

1/ it's not just about nested routes, it's about nested and concurrent views. we need a better way to serialize the current (complex) view state in the url and deserialize it when the url is changed or page is reloaded. we also need to be able to generate these urls so that they don't have to be handcrafted in templates. All of the current features like deeplinking, pushState + legacy browser fallback, cmd-click opens a new tab, etc

2/ to get this right, this should be a green field project without worrying about backwards compatibility

3/ the original proposal in 3.1. looks too simplistic, while I don't have first hand experience with embers routing from what I read it looks worthy looking at as it solves some of the problems described above. 3.3. is serverside and thus mostly irrelevant

have you looked at https://github.com/yaptv/StateTree it looks promising

@jeme
Copy link
Contributor

jeme commented Jan 29, 2013

the original proposal in 3.1. looks too simplistic, while I don't have first hand experience with embers routing from what I read it looks worthy looking at as it solves some of the problems described above. 3.3. is serverside and thus mostly irrelevant

@IgorMinar

Embers syntax (as I know it) is somewhat like:

articles: Ember.Route.extend({
    route: '/admin/articles',
    initialState: 'index',
    index: Ember.Route.extend({
        route: '/',
        connectOutlets: function (router, context) {
            "use strict";
            router.get('applicationController').connectOutlet('toolbar', 'articlesToolbar');
            router.get('applicationController').connectOutlet('main', 'articles');
        }
    }),
    list: Ember.Route.extend({
        route: '/list/',
        connectOutlets: function (router, context) {
            "use strict";
            router.get('applicationController').connectOutlet('toolbar', 'articlesToolbar');
            router.get('applicationController').connectOutlet('main', 'articles');
        }
    })
});

To me, that is quite similar to the syntax in 3.1 except that it encapsulates a hole lot of other "fields" into each individual route, but I see that as an non-issue as they are passed through gracefully, so in order to bring it to a "state based" pattern we would just need some other fields instead of the controller and template.

Right now I don't see any advantages of having named routes (articles, index, list) as above over just defining the actual route ('/admin/articles', '/', '/list'). That would bring us to a syntax as:

.when('/article', {
    connectOutlets: ()=>{}, //Sorry, TS / ECMA6 notation
    b: 42
    default: '/', // -> Could be inferred that if there was no explicit default,
        // and a had an "empty: '/'" subroute that it would be default, 
        // or the first sub-route could be default.
        // Somehow I don't particular like that we have to provide defaults here though, 
        // when the parent state is created shouldn't that know it's default at creation time?
    subroutes: {
        '/' : {
            connectOutlets: ()=>{},
            b: 42
        },
        '/:articleId' : {
            connectOutlets: ()=>{},
            b: 42
        },
        '/categories' : {
            connectOutlets: ()=>{},
            b: 42
            default: '/',
            subroutes: {
                '/' : {
                    connectOutlets: ()=>{},
                    b: 42
                },
                '/:categoryId' : {
                    connectOutlets: ()=>{},
                    b: 42
                }
            }
        }
    }
 });

So the syntax could encapsulate the same set of information to me, unless there is something I am missing in the way Ember work?... The only less simple structure is a Graph, will we have the need for that?

Anyways... I would still like to keep the principal of keeping the knowledge of the "left hand" object out of the router, so the "subroutes" parameter actually bothers me just a little, just not enough at the moment... Instead I would like the router to be able to just give as rich as possible information about what changed in the URL... And the above for now should be all about augmenting the input in a way that we can define the granularity of the "change-information" we receive.

This could then be handed to either a Controller where the developer was free to do with it what he wanted, or he could include a custom directive/set of directives which was a simple "first" implementation, or finally a state machine (loaded or defined by a directive??), that would then activate/call handlers, connect viewports, load templates etc.

Basically what I would like to see is a router that only cares about routes, and leave the other part of the implementation to whatever comes after the router. This would separate responsibility in a more healthy way in my mind.

To do that the right way, template handling would have to go from the current RouteProvider, but other than that, it is properly not that far of. I don't see the need for a grand new design on that part.

What would your thoughts be on that as an idea of separating concerns?

@nateabele
Copy link
Contributor

@IgorMinar Thanks a lot for the feedback, that's definitely helpful. Basing the routing engine on a state machine was definitely the direction we were thinking.

3.3. is serverside and thus mostly irrelevant

I brought this up as a structure/syntax example, as it solves many nesting problems that the proposed implementations don't.

Anyway, thanks again for the feedback.

@michaelwinser
Copy link

I've looked at StateTree and Stativus. I'm currently experimenting with Stativus. I think the differences are probably a matter of preference but StateTree is clearly focused on a subset of the problem:

StateTree was developed for managing the state of a typical client-side UI where the user is able to navigate around the entire UI. There are few illegal state transitions in such a scenario. Rather than have the user wire an event for every transition, you simply goto the state you would like with state.goTo() There is one function to restrict state transitions: onlyEnterThrough.

I think that the Angular way here will be to create providers that work together to solve this problem but still allow some flexibility and replacement. Comparing StateTree to other systems has helped me identify the following component roles:

  • The state manager. This is the "model" of the UI. This can be simple (single concurrent state, no hierarchy) or complex (state chart with concurrent and hierarchical states). It can have rules or not.
  • The event system. An obvious choice is to use or build on top of the angular eventing system. Another of my experiment goals is to see how well the scope hierarchy aligns itself with the state hierarchy.
  • Data model integration. The overall application state is defined by the UI and the model. Any non trivial app is going to want to parameterize UI state changes with model state.
  • pushState integration. As Igor put it, this is about serializing some of the application state to and from URLs

I'll also add some obvious observations:

  • There can be only one. The association of the state manager with the browser pushState all but requires that this be a singleton. While I can imagine a system of nested state managers organically co-existing, I'd rather not use such a system. Better to have all the states and substates managed in a single place even if they may ultimately be declared across multiple components.
  • Application state is typically composed of:
    • UI state. This is serialized by value in the URL
    • Model state. This is serialized by reference in the URL
    • User state. This is a special case of Model state. Although it's not serialized into the URL (even by reference) it is part of the context of every request (assuming some kind of login) and should be treated like model state.
  • Not all of the application state should be serialized in the URL. In particular I think that trying to serialize concurrent states will end up with URLs that start to look a lot like ASP.NET's _VIEWSTATE and we really really don't want to go there. There's a point at which that information should be treated as model state.

I'll be experimenting with this over the next week. I have project deadlines that are wreaking havoc with the time I'd like to spend on this but the ad hoc approach I hope to replace is increasingly fragile.

Michael

@ProLoser
Copy link
Member Author

Thanks @IgorMinar

I'm going to go ahead and close this issue as I don't think the core team has the time to keep an ongoing dialogue, but we were able to address what I felt to be the pressing concerns and was even provided a good starting point.

@gregwebs you are more than encouraged to join the team too and help us figure out where to go from here.

I am going to step down from the leadership role other than to in an advisory capacity. I encourage everyone to take liberties but above all else try to work in a democratic capacity. I have spoken with @nateabele about helping to ensure the project retains a forward momentum as I respect his work both on CakePHP and Lithium but again all projects on AngularUI are wholly democratic so this is a guidance capacity.

Please refrain from any further comments on this thread

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

5 participants