angular-ui / ui-router Goto Github PK
View Code? Open in Web Editor NEWThe de-facto solution to flexible routing with nested views in AngularJS
Home Page: http://ui-router.github.io/
License: MIT License
The de-facto solution to flexible routing with nested views in AngularJS
Home Page: http://ui-router.github.io/
License: MIT License
So I only recently started using Github milestones on AngularUI, and I must say it makes things a lot more chronologically organized.
It lets me quickly pull up all the issues I want to tackle immediately for the next release and also lets me have a place I can throw long-term ideas that I may pick up in the future.
I'm going to create a v0.1.0, v0.2.0 and 'future' milestones.
Things that are MISSION CRITICAL belong in v0.1.0, keep this as minimal as possible because we want to keep the scope small. Once v0.1.0 is released, we will open a v0.1.1 for bug fixes that (also) should get merged into v0.2.0.
Nice features that would make the basic functionality easier/beter can go into v0.2.0 but leaving them out will not make the router impossible to use.
Any ideas that may require us to come back to in the future should (obviously) go in 'future'.
The reason I am not using v1 and v2 is because we would like to reserve the right to keep the API unstable until we know what we're going to officially go with.
Since I don't have a lot of time, I will leave it to you guys to organize the issues into their relevant milestones.
Also, we should remove the 'review later' tag in lieu of the 'future' milestone.
I realize that issues may not be granular enough to fall into milestones yet, so feel free to leave them out until this becomes clear.
falls in ie7-8
https://github.com/angular-ui/router/blob/ui-states/src/urlMatcherFactory.js#L76
https://github.com/angular-ui/router/blob/ui-states/src/urlMatcherFactory.js#L77
while ((m = placeholder.exec(pattern))) {
id = (m[1] != null) ? m[1] : m[2];
regexp = (m[3] != null) ? m[3] : '[^/]*';
(m[3] != null)
works differently in ie7-8 and other browsers ...
Is there's a discussion list for ui-router? I can't find one.
For a single tab, it's easy, url can be like /tab/:tabId
<tab header/>
<ui-view>
How about two sibling tabs though?
<ui-view="tabOne">
<ui-view="tabTwo">
But how do you define the states? And url? "/tab/:tabOne/:tabTwo ? Is it supported?
This is a thread to keep the idea of inferred state properties alive. The idea is that we'd do some of the work for the user based on the the state name. To pull from another issue:
I also like the idea of inferring things (similar to Ember) but that's not really what angular is all about. In ember you have to always remember all the magic that is happening for you, in angular there is a lot less "magical" inference. So I'd be cautious to automatically load templates based on state name, e.g. 'contact.list' automatically loading 'contact.list.html'. If we did infer templates though, we could handle named views similar to the view's absolute name, e.g. 'menu' view in 'contact.list' could automatically load '[email protected]' though that would screw up alphabetic sorting of the files, so maybe '[email protected]'.
Benefits:
Downsides:
Questions:
The image url in question is:
https://raw.github.com/wiki/angular-ui/router/MultipleNamedViewsExample.png
I've been experimenting with the new routing code and I've managed to get pretty far in converting an existing application to use the new code but I've run into a bit of a problem and I'm not sure if it is because I am doing something wrong or if it is a bug.
The issue is that $stateParams nor anything that I can see in $state has the URL parameters for the view that is being transitioned to when attempting to resolve a nested view. You can see this issue in the example application and I created a branch that demonstrates it here: https://github.com/robschley/router/blob/stateParams/sample/index.html#L115
The contacts.detail view defines dependencies to resolve before initializing the controller. To effectively resolve those dependencies, one would expect that $stateParams or $state would provide the URL parameters for the view that is being transitioned to. In this case, contactId should be available in $stateParams. When resolving "something" in the sample, there seems to be no way to get to the contactId because it is not populated into $stateParams until AFTER all of the dependencies have been resolved.
Is this a bug or am I doing it wrong? Any guidance is much appreciated.
the following code from the docs throws an error
Error: Unknown provider: titleProvider <- title
$stateProvider.state('contacts', {
template: '<h1>{{title}}</h1>',
resolve: { title: 'My Contacts' },
controller: function($scope, title){
$scope.title = title;
}
}
after looking at the source code, I see the docs should say:
$stateProvider.state('contacts', {
template: '<h1>{{title}}</h1>',
resolve: ['$scope', function($scope){ $scope.title = 'My Contacts'; }],
controller: function($scope){
$scope.title = title;
}
}
Is it possible to make ui-view directive hook-able (e.g. with another custom directive in ui-view attributes or with view config) to implement custom views transitions (like github src tree navigation or mobile sliding).
Something like http://ajoslin.github.com/angular-mobile-nav/ , but with ability to amend transition behavior with js.
As per this thread we have been talking about having an AngularUI Org-wide hangout. I figure you guys may not be receiving emails from the google group so I thought I'd post this here:
http://doodle.com/2abdy3tkwbatrcs9
We can refine the time further once we get a general slot identified. If too many people cannot make any of these timeslots we can make a new poll.
NOTE: PLEASE UPDATE YOUR TIMEZONE FIRST BEFORE EDITING
I see the doc markup in some of the files and I see a commit called "Generate some docs via jsdoc" but I am not seeing any docs, nor am I seeing any final builds. Are you not adding some things to git?
I think the loading indicator could just be a loaded
property that is true once all views and dependencies have been loaded and resolved. The you can use the property in you templates to show some indicator if loaded while false. I think this should be a separate feature request because its SO common.
Also, Maybe a directive to automatically display a "loading.html" partial or have it be a setting on each state?
I hate to be that guy, but unit tests are really really needed. I'd be willing to help with these if the APIs are final.
It would be absolutely amazing if we could detect when the back button is pressed, using window.onpopstate
on newer browsers.
Then once ngAnimate is in, we could have transitions between pages that look different depending on forward or back (eg github file browser, any mobile app).
I'd be willing to work on this.
If the url contains a trailing slash the state routing does not recognize the url and transition to the correct state.
For example, if you define the following state:
$stateProvider .state('contacts', { url: '/contacts', templateUrl: '/contacts.html', controller: 'ContactsController' });
When you go to #/contacts it routes to the 'contacts' state correctly, however if you go to #/contacts/ the route is not recognized.
The only workaround I have found is to define a second route which contains the trailing slash with a different name but that is quite cumbersome to have to do for every single state in an application.
Thanks!
It would be absolutely amazing if we could detect when the back button is pressed, using window.onpopstate
on newer browsers.
Then once ngAnimate is in, we could have transitions between pages that look different depending on forward or back (eg github file browser, any mobile app).
I'd be willing to work on this, has anyone else done anything with this?
While writing up the Overview, I feel like targeting unnamed views or states needs a less magical elite solution. While using empty can still be an option it may be nice for developers AND any developer reading the code later if we had an alias as well.
I propose using for unnamed views and for root state (or something similar). Reference the Named Views section of the overview. Like this:
$stateProvider
.state('contacts.detail', {
templateUrl: 'contacts.detail.html'
views: {
"info" : {} // relatively targets the "info" view in "contacts.detail" state
"" : {} // relatively targets the unnamed view in "contacts.detail" state
"detail@contacts" : {} // absolutely targets the "detail" view in parent "contacts" state
"<unnamed>@contacts" : {} // absolutely targets the unnamed view in parent "contacts" state
"status@<root>" : {} // absolutely targets the "status" view in root unnamed state
"<unnamed>@<root>" : {} // absolutely targets the unnamed view in root unnamed state
});
Side Question: How do we set a root state without using URLs?
Discussion on how augment route definition (regexp, optional params, constraints,...)
We should agree in the following, in no particular order:
We could use the following pull-requests as a guide:
Essentially we need some up-to-date documentation, but by 'demo snippets' I'm referring to how different features and edge-cases are to be addressed.
Discussion on how to implement a state-based route provider. The idea is to generate a module that can be loaded on those apps who require advanced or state-based routing.
Backward compatibility does not need to be kept, so we can explore any proposal without being restricted.
Some reading to getting started:
Using the sample app you provide :
.state('about', {
url: '/about',
resolve: {
something: function() {
console.log('about');
}
},
templateProvider:
['$timeout',
function ($timeout) {
return $timeout(function () { return "Hello world" }, 100);
}],
});
console.log is called twice.
It doesn't happen when using views property on state though :
state('contacts.detail', {
// parent: 'contacts',
url: '/{contactId}',
resolve: {
something: function() {
console.log('only called once');
}
},
views: {
'': {
templateUrl: 'contacts.detail.html',
controller:
[ '$scope', '$stateParams', 'something',
function ($scope, $stateParams, something) {
$scope.something = something;
$scope.contact = findById($scope.contacts, $stateParams.contactId);
}],
},
'hint@': {
template: 'This is contacts.detail populating the view "hint@"',
},
'menu': {
templateProvider:
[ '$stateParams',
function ($stateParams){
// This is just to demonstrate that $stateParams injection works for templateProvider
// $stateParams are the parameters for the new state we're transitioning to, even
// though the global '$stateParams' has not been updated yet.
return '<hr><small class="muted">Contact ID: ' + $stateParams.contactId + '</small>';
}],
},
},
})
Discussion on how enhance the default route provider with hierarchical routes in a backward compatible way.
Task list:
Requirements extracted from the wiki and #1:
$routeProvider
service nor the ngView
directive. Let's just use uiRouteProvider
and uiView
instead (or whatever you want).route
param object.It may be nice to be able to access the parent, root and children states of any given $state.
Hi guys,
I tried to use ui-router with require.js today. The problem is, every time I inject ui.compat into the controller the specific parts stops working. I created a plnkr here:
http://plnkr.co/edit/tbf5oXZrZh7b7pJnCila?p=preview
When you take a look at main.js and add the following lines:
function (app) {
return app.run(['$rootScope', function ($rootScope) {
console.log($rootScope);
}]);
});
Instead of the current, which look likes this:
['ui.compat', function (app) {
return app.run(['$rootScope', '$state', '$stateParams',
function ($rootScope, $state, $stateParams) {
console.log($rootScope);
}]);
}]);
Then you can see that app.run(); is executed. The same is valid for routes.js. As soon as I remove ['ui.compat'...] everything works as expected again. With ['ui.compat'...] it stops.
Any idea why this happens?
Look at the ability to reject state transitions, even though in my mind this has some caveats
I'm happy to see @ksperling and @timkindberg have been moving this along.
I started this project because I wanted a routing solution that AngularUI could officially stand behind rather than have 20+ solutions that I couldn't really support or suggest to people.
That being said, I briefly spoke to @nateabele and he seems to think you guys are heading in the right direction.
I have 2 proposals:
@ksperling and @timkindberg if you'd like to briefly summarize the new proposal here for everyone.
Since I haven't been able to dig into the solution yet, I'd like the community to decide if this is the right direction
If it is...
This of course may be rejected, as everyone is entitled to own their own project.
However I would like to have an official AngularUI project for routing that we can help review and collaborate on. @ksperling as with all AngularUI projects you would still have control over and be able to manage the project, but this way we can get a bigger team on board to actively help you once this solution takes off.
We would be able to help clean up the project and bring up code quality standards as well as tie it into the AngularUI which will help with getting the word out!
I know we went back and forth on this several times already, but I think I may have found a need for this feature again.
It seems as though we are trying to get to a place where states can function completely on their own without any url routing (correct?). So how would we know which child state to load automatically without specifying a url
of ''
? Seems like we would need a default
boolean property or something similar.
Let me also attempt to define abstract states, and non-abstract parent states. Please let me know if I'm on the right track.
Abstract State
transitionTo
method) without activating one of its children.url
or default
property)default
child state is set, first child state found will be used as defaultNon-Abstract Parent State
transitionTo
method or url), though any view directives will not be populated until navigation to on of it's child state OR one of its child states is set as default child (either with empty url
or default
property)@ProLoser: It's interesting reading your solution, as I was working on my own, which is quite similar. I didn't want to pollute #1 with my code ideas below, so I thought a new topic to discuss the interface might be helpful. Personally, once I know how I want to start using something, it makes it a lot easier to understand how to go about implementing it.
So, here's what my idea looked like:
.when('/long-form', {
templateUrl: 'views/long-form.html',
controller: 'LongForm',
resolve: 'getSomeData',
andWhen: {
'/:step': {
templateUrl: 'views/long-form/step.html',
controller: 'LongFormStep',
resolve: 'getSomeMoreData'
}
}
})
These andWhen
s can be nested deeper, following the definition of the route object.
behaves as normal
/long-form
$route to array of dependenciesandWhen['/:step']
$route to array of dependencieslong-form.html
and link to LongForm
scopelong-form/step.html
and link to LongFormStep
scope*/long-form.html
would have already been resolved, compiled, and linked to the LongForm
controller.
andWhen['/:step']
$route to array of dependencieslong-form/step.html
and link to LongFormStep
scopeHere's what the template HTML would look like, adding a new route
directive to embed the views.
<h1>Awesome Form!</h1>
<div>
<p>Thanks, {{name}} for filling out our form! You're just swell.</p>
<h2>Here's what you've filled out so far!</h2>
<ul>
<li ng-repeat="field in data">{{field}}</li>
</ul>
<form>
<route root>
<p>Since this is your first time here, we need some basic information.</p>
First Name: <input ng-model="data.firstName">
Last Name: <input ng-model="data.lastName">
</route>
<route view="step" />
</form>
<marquee>This should never skip a beat!</marquee>
</div>
When long-form.html
is compiled, only the matching route
directive would be included. So, when a user is loading /long-form/first-step
, long-form.html
would compile the <route view="step" />
. The value of the view
attribute is connected to the andWhen
key. That way, when <route view="step" />
is compiled, it knows where to grab the template from. Then it's business as usual for the injected template and controller.
I wish I had time to contribute more on this. My 11 week old daughter thinks I love JavaScript more than her, so my hands are tied. There are obviously a lot of changes that would need to be made for an idea like this to work. Is this within the scope of what this project and its team are attempting to accomplish?
Thanks everyone for taking on this issue! I look forward to following the progress and hopefully spending time helping out.
transitionTo() is a fairly low-level method in that it expects a "fully qualified" state and all parameters to be passed in. I want to add a higher-level method on top of it for everyday use where you can do stuff like
<!-- Maybe '@' could be short-hand for ($state.current.name + '.') ? -->
<button ng-click="$state.go('@edit')>Edit</button>
If you have a .state('mystate', {controller: 'MyCtrl', url: '/a/{id}'})
, then navigating from /a/1
to /a/2
does not trigger a controller reload. This appears to be by design (
ui-router/src/viewDirective.js
Line 25 in c85f721
I can think of two ways to implement this: a $state.reload()
function, or a reloadOnParamsChange
param to state (similar to reloadOnSearch
). I can submit a PR that implements one of these if you think that is the right approach. If I am approaching this wrong, please let me know.
BTW, great project! Thanks!
I see the following error in the console:
Uncaught SyntaxError: Variable '$ViewDirective' has already been declared angular-ui-states.js:974
Uncaught Error: No module: ui.compat angular-1.0.4.js:1060
This error also occurs for my own app when I try to use ui-router.
I get this error on Chrome Canary on Windows 7 64 bit. Firefox stable on Linux Mint works fine.
I get the same error as above when I try to run my own app with ui-router
on Chrome Canary.
Commenting out the forward declaration of $ViewDirective
gets rid of the error in the console, but nothing seems to happen in my app - no views get populated or controllers instantiated, etc.
I have this code below:
$stateProvider
.state "standard",
abstract: true
templateUrl: "assets/layouts/standard.html.haml"
views:
"header@standard":
templateUrl: "assets/layouts/header.html.haml"
"navigation@standard":
templateUrl: "assets/layouts/navigation.html.haml"
"footer@standard":
templateUrl: "assets/layouts/footer.html.haml"
When i try to load the corresponding page, which has "standard" as its parent, the lone 'templateUrl' ("assets/layouts/standard.html.haml") will be ignored and the standard.html.haml template won't be loaded.
However when i commented out the views, that templateUrl attribute will work normally.
Is this an intended behavior? can you elaborate on this?
The core team is interested in getting involved, but they asked that we try to make a very SHORT breakdown of what issues/features we are trying to address and how the new router accomplishes this.
Awesome work, guys!
For me the only concern about Angular was routing.
I was able to implement all kind of requirements with low level js
(browser events and dom manipulations), but its not mixable with angular.
Your solution is almost perfect. I'd like to participate at least as tester :)
Some points:
1: would be great to have "more modularity" for states definitions. for example ("pseudoapi"):
// basic structure in main /app.js file
$stateProvider
.state('admin', ...)
.state('admin.profile', ...)
....
// in separate src file e.g. '/admin/profile.js'
$stateProvider
.branch('admin.profile')
.state('photos', ...
.state('photos.details', ...
// maybe also extend properties
$stateProvider
.branch('admin.profile', {...}) // "inline"
.config({ onEnter ... }) // or "explicit"
.state...
and some base configuration
$stateProvider.init({
default: 'public', // instead of $urlRouterProvider.otherwise('/')
base: '/routing/sample' // for $locationProvider.html5Mode complete urls
})
2: what about 'reloadOnSearch' ? - should it be implemented ?
3: does it make sense to amend form directive to use "native like" action syntax:
<form name="myForm" action="/user/auth/submit" method="get|post">...
to "navigate" to state on submit with form fields in params
4: is it possible to make ui-view directive hook-able (e.g. with another custom directive in attributes or through view config) to implement custom views transitions (like github src tree navigation or mobile sliding)
5: question - is it possible to move resolve:
functions definitions from state tree to some module to reuse it in different states (without polluting global namespace) ?
Really appreciate any comments.
Need to put together a demo site with mini docs. I realize this is redundant to the existing docs and approaches, so do not prioritize it.
The shim to implement the $routeProvider API on top of $stateProvider is mostly there:
I see in the example there are two very similar services, $routeProvider and $urlRouterProvider. What is the difference between these and the purpose that each serves? I'm also asking for my overview documentation.
I see you've go an onEnter callback. I'd like to request something similar, but at the global level, so all state transitions need to pass the before filters before processing the route.
The main use case I'm thinking about are
I was just sketching out my own ideas for this before googling to find this router project (looks great, can't wait for it) which would look something like this in my head... (obv not using $routeProvider, but you get the point)
$routeProvider
.before(function($route) {
if($route.current.secure && !$rootScope.currentUser) {
// abort the current route
// force login here
}
})
Any appetite for including this sort of functionality within your router project?
I think the big difference over onEnter is the ability to abort routes, and do it on all states
I'm creating this issue so that people can have a place to request joining the AngularUI Router development team!
Simply add a comment below and if possible add your 2c to issue #1
Hi,
Maybe its too simple and I am doing something wrong here.
In the code below, I have am loading templates into my views. Note that, between the two states - customers & services, only the view 'maincontent' is changing. The view 'leftpane' does not change.
.state('customers', {
url: '/customers',
views: {
'leftpane': {
templateUrl: 'ui/p-leftpane-cust.html'
},
'maincontent':{
templateUrl:'ui/p-customers.html'
}
}
})
.state('services', {
url: '/services',
views: {
'leftpane': {
templateUrl: 'ui/p-leftpane-cust.html'
},
'maincontent':{
templateUrl:'ui/p-services.html'
}
}
})
My question is can I do something like -
.state('services', {
url: '/services',
views: {
'maincontent':{
templateUrl:'ui/p-services.html'
}
}
})
where the 'leftpane' view is inherited from its previous state/last loaded state? When I try to do this, the 'leftpane' is updated to empty.
Add a directive that understands the same short-hand syntax as issue #15 and can be used to generate hrefs.
<a ui-state-ref="@edit">Edit</a>
http://angular-ui.github.com/ui-router/sample/#
Uncaught SyntaxError: Variable '$ViewDirective' has already been declared angular-ui-states.js:974
Uncaught Error: No module: ui.compat angular-1.0.4.js:1060
Hey @everyone, @ksperling is having a kid like any moment now. So he will be much less active due to his new fatherly duties. Congratulations to him and obviously we all wish his family the best!
I am trying to protect certain routes/states from users who are not logged in/don't have access to the rest server.
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.
Hi,
Something we do in CRUD environments is to include JavaScript routines for a specific <div>
partial, so that we can control everything going on inside the partial, for example:
------- start html document ------
<script type="text/javascript">
function MyCtrl($scope) {
. . . JavaScript functions . . .
}
</script>
<div ng-controller="MyCtrl">
. . . various . . .
</div>
------- end html document -------
Notice that MyCtrl is a controller that is inside the HTML document.
This enables us to have different developers writing specific business logic for each CRUD section.
I would like to use the "templateUrl" option so that we can load an xxx.html
, in which we can add as many <script type='text/javascript'>
with embedded controllers and other JavaScript code bits.
In other words, the classical ui-router just needs:
.state('report',{
views: {
'tabledata': {
templateUrl: 'MyXXX.html',
NO NEED FOR CONTROLLER HERE,
BECAUSE JS CODE IS EMBEDDED IN 'MyXXX.html'
}
},
'graph': {
templateUrl: 'report-graph.html',
controller: function($scope){... controller stuff... }
},
}
})
Thanks,
Marcus
First and foremost, thank you guys for your hard work I am loving it, it's awesome !
Is there currently a way to pause the state change to enable a "transition-out" of the current view for x millisecond ( the time the "transition-out" takes ) and resume the state change ones it's done ? I have tried $stateChangeStart event.preventDefault() but it didn't stop the transition the view and the scope was destroyed.
@ksperling said somewhere at some point:
Finally, to provide utility directives around ... highlighting the current place in the UI ...
I propose a directive called ui-active-highlight, it would add an "active" class onto the element whenever the state in the parameter was active.
<li ui-active-highlight="contacts">
<a href="/contacts">Go to Contacts Page</a>
</li>
Lets put the code in here so we can start cleaning it up and refactoring.
Since not everyone is in consensus we may try to bring it in line into a solution everyone can agree with.
Object-based states are already supported, but we should consider the pitfalls of doing it this way.
var states = {};
states.contacts = {
name: 'contacts',
url: '/contacts',
abstract: true,
templateUrl: 'contacts.html'
}
states.contacts.list = {
name: 'list',
parent: states.contacts,
templateUrl: 'contacts.list.html'
}
$stateProvider
.state(states.contacts);
.state(states.contacts.list)
Potential Pitfalls:
list
property in the future).One suggestion was prefixing all API properties with '$', though this doesn't seem optimal.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.