-
Notifications
You must be signed in to change notification settings - Fork 3k
Reducing Complexity #174
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
Comments
Complexity 1: Users not aware that url gets automatically appended to parent. This mixed with abs vs. rel urls causes confusion. Perhaps users will be more comfortable will one of the following solutions. Potential Simplifications:
|
Complexity 2: Perhaps users will be more comfortable will one of the following solutions. Potential Simplifications:
|
I actually like this idea quite a bit. Another thing that was brought up was the whole linking issue, which I've been slacking on the directive for. Once that's done, it should make that whole aspect fairly straightforward.
I'm actually not even convinced we need that. I've certainly never found a use for it. View hierarchies are de facto independent from states as it is, and coupling them just adds an unnecessary layer of complexity. |
Complexity 3: Perhaps users will be more comfortable will one of the following solutions. Potential Simplifications:
|
So how would we target views then? Just by name alone? |
Yup. Target by name, and use dot-syntax for nesting. They could be absolute by default, and use the same character as URLs to inherit from the parent. |
I think there are 3 aspects to perceived complexity:
I'm going to try to address them individually. Anything that is diffferent than that to which people are accustomed... Opportunities to make the API match what an app developer is thinking about @timkindberg wrote: "Default all urls as absolute unless a special modifier is used, basically reversing current implementation. So url: "/home" would be absolute and url: "&/home" would be appended. I took the idea of using & from LESS. +$0.02! Anything that is diffferent than that to which people are accustomed...
Might it help if an object/property hierarchy were available to the app developer at runtime?
For sure.
Sensible Defaults with Overrideability As above, I'd say start with the core v1 router. $stateProvider/$state should support its API out of the box. The presence of configuration options supplied to the provider or that appear in state definitions would trigger anything beyond the existing behavior. Make pretty much everything that UI-router does above and beyond the core router an override of the default (stock v1) behavior, and make it's the override overrideable for ultimate power -- option (a) you get basic behavior; option (b) you pick a "fancy" behavior from $state's built in fancy behaviors; option (c) you create you own "fancy" behavior and plug it in. People who stick with (a) never need to worry about (b) and (c) if they're done as overrides. Documentation Great documentation is so good that it doesn't even seem that special... because it makes the system being described seem so simple that it wouldn't have needed documentation. That's really hard to do, especially when you know the innards of the system being described. The ui-router documentation was more or less fine for me when I picked it up. I read 8 pages and then looked at the sample contacts app and still refer every once in a while to something or other on one of those 8 pages, even though it's a tossup as to whether it would be easier for me to look at the source code now that I'm kind of familiar with it. So if I'm looking at the docs when I could look at the source, they're already pretty good. Aside: while content is ultimately more important than style, I gotta mention docular. I'm just getting my feet wet with it, and at present it can't just spit out documenation compatible with gh-pages, but a conversation about documenting angular stuff can't omit docular. Anyway, to ignore the delivery/authoring format and focus on content... I think there may be opportunities to slice some guides out of a detailed API reference... One guide would be toward using $state(Provider) in a manner that's equivalent to what you get with the stock router (and ideally if $state is backward compatible, this would be a short tutorial!) -- let's call that the "base tutorial". Other tutorials could start with the result of the "base tutorial" and show how to use one additional feature of $state each. So, one tutorial for configuring a child state, one configuring a state with two views, etc... although that could end up with a lot of tutorials, the time might pay off... I'm actively pursuing making docular-generated documentation gh-pages-compatible (essentially, making it run in hash mode without an active server), and planning to document my offshoot of ui-router, so I might be able to pitch in with chunks of documentation at the API level fairly soon, even my tutorial/guide content would be divergent. |
This could not be more wrong. Angular's existing routing infrastructure is severely limited, and by being URL-centric instead of state-centric, it is wrong in its fundamental concept. Backwards-compatibility with the existing API needs to be broken. Trying to build incrementally upon a fundamentally broken concept is difficult and awkward, and just ends up being confusing and frustrating for people coming from the old system. Anyway, we've already had this discussion, and that ship has sailed, so I don't think it's worth talking about. We have an existing compatibility layer that is more than adequate. |
Okey dokey -- didn't know about that. |
Well hold on @nateabele. @stu-salsbury had great points, and i find myself in deep alignment with his vision. Maybe he's off base a tad about matching the core router API 1-to-1 (which I'm not decided on), but i think he's also saying our router should at least cover everything core router can do for folks who just want simple, plus more. I think he's just spelling out "simplicity" from a high level. I have much more I want to dive into in response to Stu but I'm only on my phone. Perhaps tomorrow. Discussions are always worth having again especially now that we are in a different place. |
I think all these points are valid... I'm wondering if it would be better to split each discussion out into a separate issue though? This thread is already getting quite long. Anyway here are my comments on all three issues listed URL complexity Absolute vs relative -- I haven't really seen anybody use absolute URLs, so making that the default seems counter intuitive. The problem with absolute URLs is that you have to repeat any parameters the parent defines. That seems easy enough when the parent doesn't have any (stuff like '/home' or '/contacts'), but in a real world app many states are going to have parameters. I think having a separate 'absUrl' property would be OK from the point of view of intent being more obvious, on the other hand it's just going to result in a bunch of extra logic and error handling (handle the case where both url and absUrl are specified). I think this can just be covered by better documentation. I think the "&/bla" syntax for relative URLs is fine. We could even encourage using both "^/abs" and "&/rel" (and start failing on unprefixed URLs at some point). That way the URLs always have some indication of how they're interpreted. Multiple views The thinking behind how the qualified view names work right now is that a parent state provides ui-view tags effectively as (named) places in the DOM, and child states fill in those places. Doing away with the idea of qualified names entirely would mean that this becomes very brittle, because it will be easy to accidentally have multiple views with the same name, especially when we implement "components" as reusable stateful entities that can be loaded into a ui-view. It would also effectively prevent us from having unnamed ui-views. I do agree that there are some improvements that can be made with respect to how views look up their content to make some cases that currently require fully qualified names to "just work". I disagree with @nateabele that nesting views should be independent of the state hierarchy. The concept of parent states providing ui-views for their children is inherently hierarchical, and this nesting approach fits very well with applications with multiple levels of navigation. The sample application (even though not a good example of a complex app) hardly uses named views at all, because the navigation and how states are nested match up. There's an anti-pattern I've seen in a few questions where people define a bunch of ui-views in their top level HTML file (e.g. top-nav, sidebar, content, footer, ...) and then each and every state populates all of those views. This means the every view is re-rendered for every state change, and it becomes difficult for a state to have a different overall layout (plus controllers become tricky because they are local to each view). If every state is really meant to re-render the entire screen, then there should be just a single top-level ui-view tag and then the state simply populates 1 view rather than 5. The main purpose of this pattern seems to be to DRY up the scaffolding of static HTML that defines the overall layout of those screen regions, but there should be a better way to achieve that without messing up the entire state/view structure in the process. I wonder if this approach is based on the fact that in $route nesting of routes just didn't make sense, whereas it is somewhat easier to understand how it would have generalized to multiple (non-nested) named views. default urls Yes, we should definitely handle the "" vs "/" case. The concept of a "start" state is somewhat misleading (except in apps where no state has a URL) because it assumes that the app is being started from it's root URL rather than from a deep link, but both those cases are equaly valid (and are really the same). In the same way a web site has no "default page" other than the home page ("/") -- the 'default' page or state is simply the one with the URL "/" because the URL doesn't contain anything else. Doing an unconditional transitionTo() in run or configure is always wrong, because it ignores the location (except in apps that don't use URLs for the state at all). So once we've treated "" as "/" I think there's essentially nothing to do here. This leaves the option open for people to have a redirect like .when("/", "/home") instead of changing the URL of the home state to "/", but I don't see any inherent advantage by having that additional redirect. backwards compatibility Agree with @nateabele -- we don't want to cripple ui-router by shoehorning it onto $routeProvider. Ultimately people will have to learn to think about states differently than they did about routes, and I think by making $state be too much like just an extension of $route we're actually making that harder for people to realize. |
If we want to provide a short cut for defining redirects, we could allow something like this
which would make $stateProvider do a |
(This won't work correctly when a child state and it's parent both have aliases though, as redirects would need to be created for all combinations of parent and/or child using any of their aliases.) |
@ksperling, that's pretty much what I did in $detour, so it looks like this for the contacts sample (ignore that this is in json format):
The aliases support the ^ syntax for specifying absolute paths if desired. |
The problems with aliases is the combinatorial explosion of rules from combining every child alias with every parent alias... in either case it doesn't seem like a particularly high-value feature. Except for providing backwards compatibility with existing URLs of your app, what's the point of aliases? |
In my corporate days people were always asking for "friendly urls" which really just meant that someone in marketing woke up thinking about how they could "improvimatize" something! I suppose the combinatorial problem that you're decribing might not hit detour because it keeps the rule (rules when you include aliases) in the states tree, so as to avoid the necessity of urlRouterProvider. In the case of my example above it's two extra UrlMatchers that are tested when the recursive tryHandle function that looks for a state that matches a url lands on the detail state. UrlMatchers are pretty lightweight as you of course know! If each alias lived as a full state with dupes of the child states rather than as an extra UrlMatcher then the combinations could indeed become weighty. Anyway, I think aliases can come in handy if you want to advertise a feature that is deep in the url hierarchy: "Get free shipping! Just go to widget.com/seenontv". And until the '' vs '/' situation is ironed out, there's always that use case, too. *EDITED for clarity on the use of UrlMatchers in states tree. It looks like right now, I do the redirect from the alias, but it seems to me that some bandwidth/time/energy could be saved by immediately parsing the parameters and transitioning to the state, then allowing the state to path up its URL once it's loaded.... I guess that'll be on my TODO list... would be nice to avoid the redirect. |
@ksperling wrote:
Insightful, well put, and important. I think I just saw someone trying to put 9 views on their base state (and there isnt even portlet support yet!) My advice is don't let this subject get lost in talk of url aliases! Nothing's more important than explaining the value of the state service and uiView directive. Without an understanding of how to use (and how not to use) them they're bound to feel complicated. |
Okay I tried splitting topics out to new issues. I'm rushing around in the 45 minutes I have between kids naps and dinner time... ugh. No f'ing time for anything. |
@nateabele you think you might be able to write some pseudo code (when you get some time!) for how we might do view targeting, based off your comment:
I'm interested in how this would look. |
@timkindberg Sure, I'll try to block off some time tomorrow to adapt some existing code I have, to put together a small example. |
Looks like everything here has either been addressed or shunted off into separate issues. Someone please reopen if I missed something. |
Complexity 2 actually never got its own issue write up, but sounds like you've got it on your mind and have been working on something anyway. |
Yeah, I have a PR forthcoming on that, hopefully today if I can finish getting the issues worked out. |
HI this view is used to other class. ex : paymentView = [paymentsdk Lesons:count]; paymentview is my local view asign to the UIView. How to remove paymentview Used to this line. |
@TamilRaja This is a JavaScript framework. You're looking for a totally different UIView. |
This is not javascript framework nateabele.. That is sdk file... |
`$scope.go()` inside the top-level run block will increase test complexity as a mock template cache would need to be set up for each test that uses `$scope` regardless of whether it depends on a template. UI Router currently uses a state using an empty `url` as the default state, see: angular-ui/ui-router#182 angular-ui/ui-router#174 (comment) Since we're setting up the layout in a parent, abstract state, redirect to the *real* index using `otherwise()`.
I ran across this issue in the angularjs core issues. angular/angular.js#1198 (comment)
The discussion evolves into a ui-router argument on complexity. Various users all acknowledge that ui-router is exactly what they need but several say its too complex. Then there is some back and forth about "no it isn't" and "yes it is" and "take it back or else!" and "who's gonna make me?".
So this discussion is opened to throw out ideas on how to reduce complexity and start thinking about cleaning up any actual or potentially confusing aspects of ui-router.
Let's list them here and as items gain traction we'll split them into new issues.
The text was updated successfully, but these errors were encountered: