ui-router / core Goto Github PK
View Code? Open in Web Editor NEWUI-Router Core: Framework agnostic, State-based routing for JavaScript Single Page Apps
License: MIT License
UI-Router Core: Framework agnostic, State-based routing for JavaScript Single Page Apps
License: MIT License
Currently if you register states with urls like:
.state('foo', {
url: '/foo/:fooid',
params: { bar: null, squash: true }
})
.state('foo.bar', {
url: '/staticstring'
})
.state('foo2', {
url: '/foo/otherstring'
})
With URL /foo/staticstring
, foo
is matched because it matches the pattern and its url rule was registered first. Currently, the first matched URL always wins.
Likewise, with URL /foo/otherstring
, foo
is matched for the same reasons.
Consider implementing heuristics where the most specific match is chosen.
/foo/staticstring
we should detect that foo.bar
is more specific than foo
.
/foo/otherstring
we should detect that foo2
is more specific than foo
.
This would have the additional benefit during lazy loading. When states are lazy loaded, there might not be a guarantee of the load order, so less specific urls could be registered before more specific ones.
It would be nice to have an interface similar to Resolve<T>
from @angular/router
for specifying resolvables and their dependencies. This is especially true now given that the AoT compiler complains on non-exported anonymous resolveFn
.
export const personState = {
name: 'person',
url: '/people/:personId',
component: Person,
resolve: [
{
token: 'person',
deps: [Transition, PeopleService],
resolveFn: (trans, peopleSvc) => peopleSvc.getPerson(trans.params().personId)
}
]
};
interface Resolve<T> {
policy?: ResolvePolicy;
resolve(transition: Transition): Observable<T>|Promise<T>|T;
}
@Injectable()
export class PersonResolve implements Resolve<Person> {
constructor(private peopleSvc: PeopleService) {}
resolve(transition: Transition) {
return this.peopleSvc.getPerson(transition.params().personId);
}
}
export const personState = {
name: 'person',
url: '/people/:personId',
component: Person,
resolve: {
person: PersonResolve
}
};
This would also enable exposing a more strict StateDeclaration
interface using Mapped Types, something like:
interface ComponentStateDeclaration<T> { // T extends Component
component: T;
resolve?: { [P in keyof T]?: Resolve<T[P]>; }
}
Allowing users to (optionally, using the stricter interface) validate that their resolve tokens match the tokens and their types of the component definition at compile time.
One open question is whether it makes more sense to have users specify sibling/parent resolve dependencies in the constructor
or the resolve
function.
The only remaining use of equalForKeys
is in StateQueueManager.attachRoute
This should be refactored to compare using Param
class, or possibly StateService.is
Before:
{ name: 'auth.login.**', url: '/login', lazyLoad: ... },
{ name: 'auth.signup.**', url: '/signup', lazyLoad: ... },
After:
{ name: 'auth.**', url: '/(login|signup)', lazyLoad: ... },
Not everyone wants to lazy load entire state definitions or trees of states.
Consider a lazy load API that allows anything such as components to be lazy loaded, without lazy loading a state definition.
The primary concern is that the current API expects the lazy load function to replace the current state. Essentially, if they state has a lazy load property, it is considered a future state and will be removed when it is loaded lazily and replaced by the new definition.
An alternate possibility is to keep a lazy load as is but do not use that as the criteria for State replacement. Instead, perhaps the states name suffix of .**
could indicate that the state is a future state, for example: mail.**
indicates that this state will be replaced by a new definition after lazy load is complete.
in .onBefore({}, hook)
,onBefore
is a transition event, while hook
is a transition hook
Named views currently target the parent state
views: {
"foo": SomeComponent
}
The above is sugar for targeting foo at the parent state, i.e.:
views: {
"foo@^": SomeComponent
}
We can also relatively target ui-views in the ancestors by adding on additional carets ^.^
views: {
"foo@^.^": SomeComponent
}
Consider a LayoutComponent
that renders like:
<div id="layout">
<ui-view name="header"></ui-view>
<ui-view name="body"></ui-view>
<ui-view name="footer"></ui-view>
</div>
Sometimes it may be useful to define a layout in a state, and also fill in the layout in that same state. However, a config like this will target the header@^
(at the parent state):
views: {
$default: LayoutComponent,
header: HeaderComponent,
}
Of course, you could target the ui-view using fully qualified state name
views: {
$default: LayoutComponent,
"[email protected]": HeaderComponent,
}
But it might be nice to have a shorthand for "target a view on the current state":
views: {
$default: LayoutComponent,
"header@.": HeaderComponent,
"body@.": BodyComponent,
"footer@.": FooterComponent,
}
[Foreword: I'm quite lost with the way the repos are organized so my apologies if this is not the right place to post this issue; please redirect me if need be]
Using Angular 1.6.1 and U-IRouter 1.0.0-beta3.
When I was mastering UI-Router legacy, I've made a habit of prefixing my resolves with an underscore character just to make them stand apart in my code. This does not work anymore with UI-Router 1.x.
Try this:
let appState = {
name: 'app',
url: '/',
component: 'app',
resolve: {
_currentUser: [ 'auth.service', function(Auth)
{
return Auth.getCurrentUser()
}]
}
}
$stateProvider.state(appState)
/* ... */
angular.module('myapp').component('app', {
bindings: {
_currentUser: '<'
},
template: '<pre>{{ $ctrl._currentUser }}</pre>'
})
the <pre>
is empty.
Now just rename _currentUser
to currentUser
(without the underscore) in both the state and component definitions, and it works.
part of ui-router/angular#21
I did some debugging and I noticed that the issue is resolved if I reset _treeChanges
when starting a new transition in Transition::startTransition
var oldTransition = globals.transitionHistory.dequeue();
if (oldTransition) {
oldTransition.promise.then(
() => oldTransition._treeChanges = {},
() => oldTransition._treeChanges = {},
);
}
Hi! Is ui-router compatible with AoT compiler from CLI?
@NgModule({
imports: [
BrowserModule,
UIRouterModule.forRoot({
otherwise: { state: 'public.home', params: {} },
useHash: false,
//configClass: MyUIRouterConfig
}),
],
declarations: [
AppComponent
],
providers: [
],
bootstrap: [ UIView ]
})
export class AppModule {}
From @Spyro92 on March 17, 2017 1:9
This is a:
My version of UI-Router is: 1.0.0-rc.1
When lazy loading states, any states registered in modules that are dependencies to the module being lazy loaded will not be registered.
in the example: lazy.foo is being registered, but not lazy.bar
it seems to be a timing issue, if you remove the dependency on lazy.bar from the module 'lazy' the state will be registered.
lazy.bar and lazy.foo should be registered
http://plnkr.co/edit/IfxBMmsZgKVAyxSZ7w0g?p=info
Copied from original issue: angular-ui/ui-router#3375
88052bf added 20+ redirect loop detection, but it only was checked
This meant a synchronous hook (onBefore
) which returned a redirect could avoid the loop detection.
Moving this logic to the Transition.redirect()
function should detect the 20+ loops at a more appropriate time.
Currently each framework implementation is copying code for the basics of creating a views:
builder. The core should provide a views
builder which does such things as transforming
state: {
name: 'foo',
component: FooComponent
}
to (essentially):
state: {
name: 'foo',
views: {
$default: {
component: FooComponent
}
}
}
Hi
we are moving to ui-router 1.0 and having issue one of browser back button click.
Here is my scenario -
user clicks a link and it goes to a state A ( let's say url http://testApp.com/#/events/all
)
Inside State A, user clicks one more link and It goes to State B.
url -> http://testApp.com/#/events/<<idParam>>
$transition$.router.stateService.target('<<State C Name>>', <<State B Param>>)
So, the last state it directs to State C and brower url showing state C url ->
http://testApp.com/#/events/<<id>>/View
As per user, url changes from State A to State C. So, when user clicks back button, he/she should go back to State A
to handle the browser back button click, we have implemented
$rootScope.$on('$locationChangeStart', (event, newUrl) => {<<logic to show confirmation pop up>>});
when code is triggering, the newUrl (above Step 5 parameter) is showing as http://testApp.com/#/events/all ( step 1 url) which is correct but some how the State B is getting loaded again and it's taking all as id parameter and calling resolve methods in StateB and failing because all is not a valid param value.
StateB has an onExit Method and I think only that should be executed not the resolve methods. and State A should be loaded but it is not.
I am suspecting issue in $transition$.router.stateService.target
which is doing redirection in onEnter (step 2 above). I tried to use location = 'replace' option but did not work.
NOTE This is only happening in chrome. Firefox is working as expected. Firefox going back from StateC to State A without any issue.
I am stuck here and any help would be highly appreciated.
Hello !
I have one state A, a child B and a child C:
A -> B -> C
In state A declaration:
name: 'organizations',
url: '/organizations',
onEnter: (trans, state) => {
if (trans.params().organization_id) {
return;
}
return trans.injector().getAsync('organizations').then(organizations => {
const organization_id = get(organizations, '[0].organization_id');
if (!organization_id) {
return;
}
stateService.go(applications.state, {organization_id}); // will work
});
},
In state A.B declaration:
parent: organizationsState,
name: 'applications',
url: '/:organization_id/applications',
onEnter: (trans) => {
if (trans.params().application_id) {
return;
}
return trans.injector().getAsync('applications').then(applications => {
const application_id = get(applications, '[0].application_id');
if (!application_id) {
return;
}
stateService.go(sessions.state, {application_id}); // will throw a "Param values not valid for state" even if application_id is perfectly valid.
});
},
In state A.B.C declaration:
parent: applicationState,
name: 'sessions',
url: '/:application_id/sessions',
// no params:{} or thing like that
When transitioning from onEnter to onEnter callback using stateService.go() the second call will throw a "Param values not valid for state" even if application_id is perfectly valid.
The workaround is to defer stateService.go(sessions.state, {application_id});
with setTimeout(() => stateService.go(sessions.state, {application_id}))
for instance.
In the current codebase, attempting to go to a state+params identical to your current state+params is a no-op. This is good and makes sense, since there's nothing meaningful to do to transition from your current state+params to your current state+params.
However if you attempt to go to a different state+params, such as by clicking on a ui-sref
, a transition is always created and ui-router starts resolving the necessary data. This causes a problem if the user tries to click the same ui-sref
twice or more - ui-router will queue up a bunch of identical transitions, waste time retrieving the same resolve data repeatedly, and take much longer to actually switch to the new state.
A request to transition to a state should therefore be ignored if either the requested state is exactly the current state or it is exactly the destination state for the current transition.
In UI Router < version 1.x, I had implemented my own redirectTo functionality in a $stateChangeStart event. One thing that I added was a 'replace' for the location parameter. eg.
$state.go(toState.redirectTo, toStateParams, {location: 'replace'});
The benefit of this was to avoid the odd glitch in browser history.
For eg. when a user navigates: was on state1 -> (navigates) -> state 2 -> (redirect occurs) -> state3
Then they click the back button in the browser.
With location: 'replace', they are taken to state 1, and skip state 2, which I think is a better experience.
With the built in redirectTo in UI Router version 1.x, this doesn't seem to be the case.
Clicking the back button causes a brief "blip", taking the user to state 2, and quickly redirecting back to state 3.
Upon clicking it again, only then are you taken to state 1 as expected.
Are there any plans to improve this? Or is there a work around to cause the "redirectTo" to perform a location: 'replace'
?
i have login folder and having login route Provider.
$routeProvider.when('/admdashboard', {
templateUrl : file_path+'/login/login/user',
controller : 'LoginCtrl'
});
app.controller('loginCtrl',function($location,$scope,$location,$http){
$http({
method:'POST',
url:file_path+'/api/v1/user/login,
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
data: $.param($scope.text)
}).success(function (data){
if(data.response != 'error'){
$location.path('/admdashboard');
$scope.$apply();
}
});
});
I can login successfully.but i am not able to direct?
After login successful how to redirect to administrator route provider without reloading the page
$routeProvider.when('/admdashboard', {
templateUrl : file_path+'/admin/dashboard/dashboard_tiles',
controller : 'AdmDashboardController'
});
After upgrading ui-router-react from 0.3.0
to 0.4.0
and ui-router-core from ^1.0.0-beta.2
to 4.0.0
, I am getting the following error messages when using router.stateService.go(statename)
or router.urlRouter.otherwise(statename)
:
Chrome
Uncaught DOMException: Failed to execute 'replaceState' on 'History': A history state object with URL 'http://taba/' cannot be created in a document with origin 'http://localhost:8090' and URL 'http://localhost:8090/'.
Firefox
SecurityError: The operation is insecure.
I am unable to share a demo on GitLab due to non-root base causing infinite redirect, but you can clone the project and run locally yourself. Run via npm install && npm run build:demo && npm run start:demo:dev
.
If you go to the localhost:8090
; the attempted redirect from /
to /taba
will cause the error. If you manually go to localhost:8090/taba
, you will see the states properly render. However, selecting a tab will also trigger the error, and the URL will not change.
Since the new core is written completely in TypeScript, there would be no need for any external typings anymore, allowing the api changes to be in the type definitions at the time of release as well, but the problem is, that no noImplicitAny
checks nor strictNullChecks
are done by the typescript compiler atm. This breaks the build for everyone using this and making it impossible to use the integrated type definitions at the time.
The problem
definitionFn
instead of the definition
objectarray: false
encode
function is never invoked during state transitions, so the parameter is not encoded correctly.The reason
Because the parameter does not declare array: false
its type is wrapped into an ArrayType
during state declaration โ thatโs before the typeโs definitionFn
is invoked.
But ArrayType
defines its encode
function (and others) based on the wrapped typeโs functions at the time when ArrayType
is instantiated. ArrayType
stores a reference to the old encode
function (which was undefined, so itโs the identity
function) instead of looking up the actual function when ArrayType.encode
is called.
Later, the typeโs definitionFn
is invoked and redefines the encode
function, but the array params still reference the identity function.
The solution
ArrayType
until after all definitionFn
s were invoked (probably compilcated)ArrayType
โs functions based on the run-time value of the wrapped typeโs functions instead of capturing them locally.The URL parsing code currently has some vestiges from when it only worked with the angular 1 $location
service.
The ng1 $location
service has one major flaw we could never work around. This was the reason the custom ~2F
encoding was created (when encoding parameter values with slashes in them).
ui-router-core
should not have special handling for encoding slashesangular-ui-router
itself should encode slashes as ~2F
string
type currently process ~2F
; rename this type to path
and make it the default parameter type for path parameters in ng1 onlyLocationService
and LocationConfig
from coreservices
to UIRouter
instance~2F
except for ng1 path paramscoreservices.location
moved to UIRouter.location.service
and UIRouter.location.config
Checkin 588dd99#diff-aa061986504f2cc13cc1174b6c24c91b has caused your unit tests and ci build to fail.
Would suggest turning on Branch protection in GitHub to ensure your build passes before allowing lands especially to master.
angular-ui/ui-router#3119
ui-router/react#11
angular-ui/ui-router#3181
If the state is defined using parent:
notation, you cannot reference it by including the parents name. For example if a state is declared like this:
{
parent: 'home',
name: 'foo'
}
And you cannot create a sref such as ui-sref='home.foo'
because home is not technically part of the name of the state.
This also affects glob patterns in transition hooks. Is not currently possible to match foo
using this criteria object:
{ to: 'home.**' }
We currently allow onBefore hooks to either synchronously return a HookResult a transition, or to return a promise. This was initially created to implement the synchronous $stateChangeStart
polyfill.
However, having onBefore be handled differently than the other hooks has caused additional edge cases, and has been at the root of a number of reported bugs. It also increases the code size and complexity. My gut feel is that removing synchronous handling code will make transition hooks easier to reason about.
I propose that onBefore
is handled as a normal async hook, very similar to onStart hooks. It seems most likely that any end users who currently use onBefore
will be unaware of the change in implementation.
Currently the only way to lazy load a future state is to activate the state. The lazyLoad transition hook handles this.
If a developer wants to preload lazy routes, they cannot.
We could expose an API to imperatively trigger a state's lazyload function
This issue is just for improving Typescript experience. There is no functional changes intended.
When working with Typescript, using Transition.params()
usually feels a bit clunky. A piece of code to illustrate the issue:
let toParams = transition.params();
console.log(toParams.id); // Warning; "prop id does not exist on type.."
console.log(toParams['id']); // ugly workaround
Both of the options above leaves the user with no intellisense in their editor. There is solution to the above, which is to cast params to interface/type, but this is messier (especially in one-liners):
let toParams = transition.params() as MyStateParams;
console.log(toParams.id); // yay!
console.log((transition.params() as MyStateParams).id); // not very pretty...
Ideally, I would like to be able to do this:
let toParams = transition.params<MyStateParams>();
console.log(toParams.id);
console.log(transition.params<MyStateParams>().id); // feels better than casting
using encodeURIComponent/decodeURIComponent
would solve the issue
The new matching functions seem to have some serious performance impact if you use many states:
Plunkr with 500 states:
Plunkr: pre 3.0.0 (beta.3) Fast URL match: angular.run reached in 2 seconds
http://plnkr.co/edit/BXsCPsh5qLiVatmavtiO?p=preview
Plunkr: 3.0.0 (rc.1) Slow URL match: angular.run reached in 25 seconds
http://plnkr.co/edit/0vb4ReYiabWsZprCrk4F?p=preview
I do use a lot of states (angular 1, 0.3.X migration) without priority and noticed this performance issue in my application.
In my team, we are trying to use webworkers but @angular/core raise an error.
Instead of window
, self
is a reference for Window or WebWorker.
Plnkr: https://embed.plnkr.co/V5p6igk2POXUhOMwH7iz/
Edit: plnkr updated
This manifests for me when running version 1.0.3 in an angular 1.x app, with e.g. states:
var states = [{
name: 'liheap',
url: '/liheap',
parent: 'app',
template: '<ui-view></ui-view>',
redirectTo: 'liheap.vendor'
}, {
name: 'liheap.vendor',
url: '/vendors',
template: '<ui-view></ui-view>',
redirectTo: 'liheap.vendor.list'
}, {
name: 'liheap.vendor.list',
...
}];
On the transition to 'liheap.vendor.list', it throws a
Object.keys: argument is not an Object
on line https://github.com/ui-router/core/blob/master/src/common/common.ts#L579 where the second argument is a string, which causes the transition to fail.
I believe the root cause is discussed here: https://stackoverflow.com/questions/31917961/object-keys-behavior-in-chrome-and-ie-11
Property 'from' of type 'string | boolean | Predicate<StateDeclaration> | undefined' is not assignable to string index type 'string | boolean | Predicate<StateDeclaration>'.
I get this error when enabling strictNullChecks
. I've worked around it with the skipLibCheck
option in my .tsconfig.json
. I see some work was done to better support strictNullChecks
, but I am still having an issue.
Thank you for your time.
Currently a transition will always supersede any transitions that started before it - unfortunately, this includes transitions which never actually started themselves, due to being interrupted by an onBefore
hook. For example, I wrote the following simple onBefore
hook to prevent several clicks on the same ui-sref
from "stacking up":
mod.config(function($transitionsProvider) {
let prevTarget = undefined;
$transitionsProvider.onBefore({}, function(trans) {
const target = trans.targetState().toString();
if (prevTarget && target === prevTarget) return false;
prevTarget = target;
}, {priority: 9999});
});
If you click the ui-sref
several times, only the first transition will attempt to fetch its resolve data (as desired), with all later transitions immediately being aborted. However, once all resolve data have been retrieved, the first transition is also cancelled since other transitions were attempted.
Since onBefore
is meant to be invoked before the transition even begins, it should be able to intercept and throw away unwanted transitions entirely, without having them interrupt other operations.
I am trying to host a UI-Router project with a non-root path in the <base>
tag:
https://wallzero.gitlab.io/ui-router-react-digest/
(I suggest observing with Chrome since it will handle the Uncaught RangeError: Maximum call stack size exceeded
without crashing)
UI-Router is then configured to redirect to TabA state. However, with a non-root base, an additional /
preceeds the route /taba
resulting in an infinite redirect between /taba
and //taba
. When it finally stops, the url is https://wallzero.gitlab.io/ui-router-react-digest/
I've tried both <base href="/ui-router-react-digest/">
and <base href="/ui-router-react-digest">
; with and without the trailing slash. It appears the urlRouter.otherwise function is prepending a /
. I've tried the following which all produce the same result:
router.urlRouter.otherwise('/taba');
router.urlRouter.otherwise('taba');
router.urlRouter.otherwise(() => {
return '/taba';
});
router.urlRouter.otherwise(() => {
return 'taba';
});
Also, a root <base href="/">
works just fine.
You can run my project yourself: https://gitlab.com/wallzero/ui-router-react-digest/tree/master. Run via npm install && npm run build:demo:gitlab && npm run start:demo:dev:gitlab
.
Uncaught (in promise) Rejection {type: 2, message: "The transition has been superseded by a different transition", detail: Transition}
With visualizer, sticky states, dsr, etc. it might be nice to have an official plugin architecture.
Something like:
import {MyCoolPlugin} from "ui-router-cool-plugin";
var router = new UIRouterReact();
router.plugin(MyCoolPlugin);
From @adamreisnz on January 19, 2017 22:43
I want to trigger a transition hook which only fires if the user enters a specific state without having a from state, e.g. they land on the page by typing in the URL or following a direct link.
I assumed this would be accomplished via:
$transitionsProvider.onBefore({
from: '',
to: 'welcome.*',
}, transition => { ... });
However, that seems to capture any transition to any welcome.*
route, as I suspect the empty from
value is being ignored.
Is there another way to have hook criteria match only when there isn't any from
state?
If not, can it be implemented so that an empty string (as opposed to undefined
/ null
) triggers this check?
The docs don't document this use case either.
Copied from original issue: angular-ui/ui-router#3285
[Using UI-Router 1.0]
I have a parent state with several child states to handle a tabbed view. The parent state redirects to the first child state using a redirectTo
property.
In an unrelated state I have a component with a uiCanExit function in the controller that shows a confirmation dialog when there is unsaved data (with cancel, discard and save). When I press discard I resolve the dialog promise to true but the confirmation dialog is displayed again. To prevent this I need to make sure that the conditions for displaying the dialog are not met.
Is this a bug or intended feature?
In angular-ui-router 0.x you could create a class for a state:
class ModalState implements StateDeclaration {
constructor(def) {
Object.assign(this, def);
}
onEnter() {
this.modalInstance = $uibModal.open(...);
thos.modalInstance.result.then(this.onClose.bind(this), this.onDismiss.bind(this));
}
}
This worked fine back then because the internal State
object's prototype was the user supplied StateDeclaration
, i.e,
var internalState = Object.create(stateDeclaration)`
but this is no longer possible because we now use new State()
to get the State
(class) prototype, i.e.,
var internalState = Object.assign(new State(), stateDeclaration);
Since Object.assign only makes copies of the stateDeclaration's own properties, it does not make copies of the prototype onEnter
function, for example.
We should switch back to the old behavior (internal state object's prototype is the user supplied state declaration). We will lose the ability to do obj instanceof State
, but that is a small price to enable numerous other convenient features.
For example, hook functions can check for user-supplied state properties without explicitly querying state.self.property
:
transitionService.onStart({ to: state => state.customflag }, ...)
Projects like sticky states can define new callbacks (like onInactivate
) without also creating a statebuilder to enable access to the stateDeclaration.onInactivate
property.
When tying to access to /account
which is lazy path it always redirect me to the static_page
export const app_states = [
{ name: 'account.**', url: '/account', lazyLoad: ... },
{ name: 'static_page', url: '/{name}', component: StaticPage },
]
to solve this the future states should be registered with the same order of it's parent or changing the matching rule
With @uirouter/[email protected]
I've been able to upgrade to the latest. I fixed the Infinite Redirect (my fault) and the History Push Error seems to be resolved with the upgrades, so I can now at least demo the project. Again, the url is: https://wallzero.gitlab.io/ui-router-react-digest/
Now it seems ui-router
does not work with the <base>
tag - even if the <base>
tag doesn't contain an href
. With the <base>
tag, every route transition triggers otherwise()
. Both go()
and a manual url will trigger otherwise()
. In the demo you'll see it is stuck on taba
. Selecting tabb
fails to resolve the route and triggers otherwise()
, making it return back to the resolve state, taba
. I'm not sure why otherwise()
is triggered, because if I call router.stateService.go()
inside resolve()
, it will complete without calling otherwise()
again.
I've also noticed if I use a <base>
tag, I have to remove the prepended /
from my root route. If I don't, an extra /
is shown after the <base>
's href
- like in the demo.
If I run locally without the <base>
tag, and return the prepended '/' to my root route, everything works properly. However, then I can no longer run on any path other than root /
.
In pushStateLocation
plugin, when setting a url with .url()
the change listeners are not called therefore the router is not synced as expected.
Given the following routes:
{ url: '/', name: 'home', component: ... }
{ url: '/{page}', name: 'cms', component: ... }
when visiting the home page in firefox the url match cms
rule first but it should be 'home'
Workaround:
- { url: '/{page}', name: 'cms', component: ... }
+ { url: '/{page}', name: 'cms', params: { page: { value: '' } }, }
core/src/state/stateService.ts
Lines 366 to 373 in 64fbfff
const rejectedTransitionHandler = (transition: Transition) => (error: any): Promise<any> => {
if (error instanceof Rejection) {
if (error.type === RejectType.IGNORED) {
// Consider ignored `Transition.run()` as a successful `transitionTo`
router.urlRouter.update();
return services.$q.when(globals.current);
}
const detail: any = error.detail;
if (error.type === RejectType.SUPERSEDED && error.redirected && detail instanceof TargetState) {
// If `Transition.run()` was redirected, allow the `transitionTo()` promise to resolve successfully
// by returning the promise for the new (redirect) `Transition.run()`.
let redirect: Transition = transition.redirect(detail);
return redirect.run().catch(rejectedTransitionHandler(redirect));
}
if (error.type === RejectType.ABORTED) {
router.urlRouter.update();
// Fall through to default error handler
}
}
let errorHandler = this.defaultErrorHandler();
errorHandler(error);
return services.$q.reject(error);
};
Current behavior is to log ABORTED rejections. Enough people have requested not to log, or been confused about how to mute them. We should change so we no longer fall through to the default error handler.
Compiling a typescript application with strict null checks enabled will produce a number of errors due to the definition of HookMatchCriteria:
ERROR in /home/schoel/Projekte/javascript/i3ge/node_modules/ui-router-core/lib/transition/interface.d.ts
(735,5): error TS2411: Property 'to' of type 'string | boolean | Predicate | undefined' is not assignable to string index type 'string | boolean | Predicate'.ERROR in /home/schoel/Projekte/javascript/i3ge/node_modules/ui-router-core/lib/transition/interface.d.ts
(737,5): error TS2411: Property 'from' of type 'string | boolean | Predicate | undefined' is not assignable to string index type 'string | boolean | Predicate'.ERROR in /home/schoel/Projekte/javascript/i3ge/node_modules/ui-router-core/lib/transition/interface.d.ts
(739,5): error TS2411: Property 'exiting' of type 'string | boolean | Predicate | undefined' is not assignable to string index type 'string | boolean | Predicate'.ERROR in /home/schoel/Projekte/javascript/i3ge/node_modules/ui-router-core/lib/transition/interface.d.ts
(741,5): error TS2411: Property 'retained' of type 'string | boolean | Predicate | undefined' is not assignable to string index type 'string | boolean | Predicate'.ERROR in /home/schoel/Projekte/javascript/i3ge/node_modules/ui-router-core/lib/transition/interface.d.ts
(743,5): error TS2411: Property 'entering' of type 'string | boolean | Predicate | undefined' is not assignable to string index type 'string | boolean | Predicate'.
This is because the type of the string keyed property ([key: string]: HookMatchCriterion
) has to match the type any other property in the interface. All other properties are optional, though, and thus of type HookMatchCriterion | undefined
. Changing the type of the string keyed property to HookMatchCriterion | undefined
resolves the issue.
Currently, if I wanted to write a transition hook for a specific state, I'd target this state like so:
{ to: 'mystate' }
But if I needed a transition for every state but a specific one:
{ to: function(state) { return state.name != 'mystate' } }
Ideally, the glob pattern matcher would accept something like:
{ to: '!mystate' } // Reject 'mystate'
This would allow interesting things like ignoring a whole path in the tree:
{ to: '!mystate.**' } // Match anything that is NOT under 'mystate'
What do you think?
Rename Globals
class to UIRouterGlobals
, then remove the interface.
Typescript can augment Classes, not just interfaces.
This allows easier injection of augmented globals (for example, for https://github.com/ui-router/rx)
If a transition's treechanges has equivalent to
and from
paths, the transition is ignored. However, sticky states uses the exiting
path to exit inactivated states even when the to
and from
paths are identical.
We should update the ignored logic to also take into account entering
or exiting
paths
In some cases, a null query parameter value does not take effect. When a query parameter has a value, and is updated to be 'null', it may not take effect.
Here is a failing unit test:
it('should not inherit previous params when new params are passed', async(done) => {
router.stateRegistry.register({
name: 'foo',
url: '?fooParam',
});
await $state.go('foo', { fooParam: 'abc' });
expect(router.globals.params).toEqualValues({ fooParam: 'abc' });
await $state.go('foo', { fooParam: undefined });
expect(router.globals.params).toEqualValues({ fooParam: null });
done();
});
FAILED transition inherited params should not inherit previous params when new params are passed
debug.js:21 Uncaught Expected StateParams({ #: null, fooParam: 'abc' }) to equal values Object({ fooParam: null }).
at Suite.<anonymous> (http://localhost:8080/base/test/index.js:20452:56)
at step (http://localhost:8080/base/test/index.js:19674:24)
at Object.next (http://localhost:8080/base/test/index.js:19655:54)
at fulfilled (http://localhost:8080/base/test/index.js:19646:59)
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.