Skip to content
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

Partial Routes #13

Open
jeme opened this issue May 1, 2013 · 13 comments
Open

Partial Routes #13

jeme opened this issue May 1, 2013 · 13 comments
Labels
Milestone

Comments

@jeme
Copy link
Contributor

jeme commented May 1, 2013

Allow for defining partial routes that can be used to initialize routes more incrementally, so that if an application begins to have a large amount of routes, they don't all need to initialize up front.

If we allow for use of services like $http etc. which returns promises, we need to integrate that so that we son't complete the evaluation until that promise has returned.

@laurelnaiad
Copy link

Hey @jeme, just getting started figuring out what you have here. Does this issue mean that right now there is only one chance to make all of the calls to $stateProvider.state() and $stateProvider.transition()? I'd like to be able to incrementally define (and maybe even undefine) routes/states based on (a) changes to the set of templates (think about a CMS where an end user can publish pages that should appear in the nav) and (b) the authorizations for a given user to traverse certain routes.

By way of being clear, I'm hoping to have a navigation service that handles "knowing" everything about the nav tree -- its hierarchy, the labels for each node in the tree, what is "next", "previous" and "up" from each node in the tree -- and to populate that tree in the navigation service based on the available content in my DB and the uesr's permissions. So what I'd like to do is have that service edit the routes/states as information changes. Removing routes isn't too important because I can redirect to a "not authorized" page if someone types them in or backs onto them after losing permission, but being able to add on the fly would be great.

If you have the time, let me know if I'm making any sense.

@jeme
Copy link
Contributor Author

jeme commented May 2, 2013

@stu-salsbury No, this issue is meant to cater far large solutions where you end up having allot of routes that could potentially cause the application initialization to take a long time.

A partial match would instead say that when say a route e.g. matches /my/route/* then go initialize:

/my/route/one
/my/route/two
/my/route/three

And then run the match. It will also lower the amount of routes it will pass through on the matching face, as it can approach it more like a decision tree.

But this is the only "on the fly" addition of routes I would recommend, and it is scheduled for the future for a reason, as there has to be put some more thought into it before the implementation can begin, it is still just an initial idea.

What you have to keep in mind when defining states/routes on the fly is if you find your self on such a state/route as a user, then hits refresh, the state/route suddenly doesn't exist as you haven't passed though the workflow that created it.

Take a look at my response in this thread, maybe it can clarify that issue: angular-ui/ui-router#95

You can still however define states/routes/transitions in different files/modules etc. but they should all be done in a config section which will then run as part of the application initialization. You need to make sure the have the dependencies in order if you separate state definitions over multiple modules.

@laurelnaiad
Copy link

I think maybe I didn't express my plans/needs very well. I don't plan to define states/routes on the fly as in "when the user requests them". I plan to do it when my site loads, but do it in a data-driven manner. My server knows what the valid routes are and can provide that data through AJAX to a service, which would then set up all of the routes. An anonymous user gets all of the anonymous routes when they land. As the user progresses through use of the system, the routes that are available can change because either (a) the data-driven routes just change (i.e. some other user who is an admin of a the CMS adds a blog feature) or (b) the user gains authority to access an already extant route.

So, to summarize/repeat: not on the fly as in "upon requesting the route" but on the fly as in "after initial app load phase and in a data-driven manner".

@laurelnaiad
Copy link

addendum -- I do also want to be able to load templates on request, but that's an entirely different kettle of fish and I'm pretty comfortable with my options there (although the navigation service would need to know when content for a given URL is versioned in order to provide a cache-busting version # url parameter to the template property of the state's view so that updates are seen).

Incrementally loading routes during the request cycle sounds great too, but I hadn't even begun to worry about that yet. So thanks for clarifying what the actual issue here is!

As you might be able to tell, my river of wants is deep and wide, so I'm hoping that I'll be able to use angular-routing and contribute as well!

@jeme
Copy link
Contributor Author

jeme commented May 2, 2013

That should be possible, but it does present it's own chalenges as the $http/$resource service isn't available on configuration/initialization time.

So you will properly have to go directly to jQuery or go more raw and create your own XMLHttpRequest to the server. But other than that, I can't really see an issue with doing that.

That is unless you wan't to do something horrific and begin to generate javascript dynamically on the server side before you post it back...

As for the template loading part, templates are only loaded from the server at the first time they are needed (provided you use the template as urls feature). That will however cache them, so if you wish to be able to reload a template at some point you would have to either use a template provider function or go through the $view service in transitions. Alternatively controllers, the later would properly be generating more boilerplate which would just obscure it all, so I would recommend the template provider function.

Perhaps I should make one able to return an object from that which could otherwise adhere to the rules, so rather than having to load the template and passing it back, one could also choose to pass back a template definition object with the URL to load, to ease things up a bit, then you would practically only need to change the #version in the template.

I am not 100% sure on how Angulars template cache works though (that is what we rely on for templates)

@laurelnaiad
Copy link

I forgot to mention: I think I'm planning to use requirejs to get templates (hence the thoughts on cache-busting) so on that front I should be ok.

For the navigation service setup: no, I certainly want to avoid generating javascript on my server (I'm using XQuery in Marklogic for the server, for what it's worth)... but I've thought about the possibility if it comes to it -- I've done it before and I know I don't want to do it again.

I think I can get away with showing a non-angular spinner wheel while the navigation service sets up. But I could be wrong...

Are you saying that my navigation service ('stuNav' or whatever), when it is initializing, can't get the $http or $resource services dependency-injected and usable? That might present (surmountable, but annoying) a problem.

Or is it that the initial page load is going to flat-out fail because there is no time to set up the routes before the module is forced to handle the request before the service has initialized them?

I'm picturing:

A user lands fresh on http://example.com/someDeep/Link . My url-rewriter maps it to index.html. My app initializes and since the module depends on the 'stuNav' service and the 'stuNav' service depends on $request. So by the time angular (or probably angular-routing) is handling the request, my routes will be in place... if I'm wrong about that then I really need to go back to the drawing board.

@laurelnaiad
Copy link

BTW: shouldn't a really big site have primarily dynamic routes, and thus
not need a ton of separately defined ones?

@jeme
Copy link
Contributor Author

jeme commented May 2, 2013

In angular, you sort of have to phases of an application. Initialization and Runtime...

During Initialization you only have access to Providers and I think it's values, this is documented somewhere at angularjs.

During runtime you have access to the services, (controllers, filters and other stuff as wel) but not the providers (at least not directly, you could work around that by initializing a provider which service would store those).

The best way I can describe providers is that they allow you to configure services before they get instantiated. The pattern sort of looks like:

function MyServiceProvider() {
   //here your in the provider, this is accessible through out the initialization face using config.

   this.get = function() {
       //when we switch to runtime, and the service is requested, this is the function providing that, after that the service is cached.
   }
}
angular.module('mymod').provider('MyService', MyServiceProvider);

The above will create to components accessible in angular.

  • Provider: MyServiceProvider
  • Service: MyService

So if i understand what you wan't correctly, you will properly need to create a navigation provider rather than a service, obviously that also ends up creating a service which you can use at runtime for things?, but during initialization it will be the provider you will need.

And since the $http is a service, you don't have access to that at this time, you have access tot he $httpProvider, but if I remember correctly, that isn't really capable of much.

This is Angular 101, but one of those things that took me quite a while to wrap my head around, and it's not that easy to explain over a text medium. (Hell, tried to explain it to a colleague today and that was even challenging.

I might also have misunderstood you completely, but it's getting late and I am sort of tired, so my apologies for that if that is the case... again... text mediums are horrible for detailed clarifications >.<...

@laurelnaiad
Copy link

Thank you. I think that's plenty to get me started in doing some research.
Your time is appreciated. I'm learning a lot about angular from
angular-routing and ui-router and the people making them. It looks like it
may take some fancy footwork to get data from the server to whatever code
populates angular-router
in time to have it ready before runtime kicks in
and something needs to be present. I can already picture the XQuery code
generating the javascript... I hope that picture doesn't go any further
than my head. After coming across a rejected pull request on something
that resembled sticky views in the angular github source, I realize that
the core team isn't too psyched about coloring outside of the lines as they
exist in the area of routing. I think I saw you pop up in that thread.

@laurelnaiad
Copy link

Please don't let me keep you awake!!!

In looking at the docs: http://docs.angularjs.org/guide/dev_guide.services.managing_dependencies

and this blog post: http://blog.jdriven.com/2013/03/how-to-create-singleton-angularjs-services-in-4-different-ways/

they make it seem that one service can use another in its factory for configuration. So unless I'm reading it incorrectly, my service wouldn't have a problem accessing $http or $resource. I may very well be reading it wrong.

However, I suppose you're may be getting either at:
a) that I won't be able to get my service initialized before the routing needs to be in place; or
b) that my service won't be able to initialize angular-routing before routing needs to be in place.

I need to look at that more. A test wouldn't hurt me at this point, if nothing else, as a learning exercise. There's still some time left in my day. I get really tired of my girlfriend demanding that I stop working late at night, so I won't tell you to go to bed, but...

@laurelnaiad
Copy link

I did some more research -- I think I might partially get it now. Your explanation was right on, but it didn't take until I read it in three or four places.

What I'm trying to do is two fold:

  • data-driven routing
  • data-driven navigational information that a view or views can use to display things like forward/next/up buttons, labels/tooltips/etc for what's next, and a dynamic navigational tree UI.

After looking a bit into how angular and angular-routing do their thing, I figured out that what they do is configure the routing as a provider, and execute it as a service. Which is exactly what you were trying to tell me that I needed to do.

So it seems like the "right" way to do what I'm envisioning is to:

  • create a data-driven navigation route+navigation service
  • create a view directive that uses it (and supports "sticky" parents)
  • create component directives that use the service to render the navigational UI elements

In other words, write YAR (Yet Another Router). :(

Or: write code to hack into the configuration of an existing router both at configuration time and whenever the data indicates the need during the normal app lifecycle. double :(

Hmm. After I decided to look for alternatives to Ember, I asked a friend of mine to call an ambulance if he hears that I'm writing a JS MVC framework, . I don't think what I'm contemplating qualifies, but it is a step in the wrong direction.

I guess I brought your issue #13 way off track. If you'd like to clean up the issue, I won't be hurt. I'm sorry for dragging my mess into it.

@jeme
Copy link
Contributor Author

jeme commented May 3, 2013

Personally, I would just write a provider that could fetch my "route/state configuration information" on the server and use jQuery to push that request, yes it's a bit of a workaround but meh...

In any case, since this issue is meant to delay the initialization of routes until needed provided that they are under a partial definition, that would happen at runtime so while it's not meant to provide a solution to your request, it might be a way to do it, although I would properly define it as a workaround. Like just defining a global /* partial route and then initialize routes inside that handler, as that would be executed at runtime instead.

So I will keep your comments and have them in mind when I start on this, but it won't be any time soon.

And on the other part, the whole Provider, Factory and Service is indeed somewhat confusing, and very much so in the beginning.

@jeme
Copy link
Contributor Author

jeme commented Apr 22, 2014

For reference: #19

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

2 participants