UI-Router for Angular: State-based routing for Angular (v2+)
MIT License
Bot releases are hidden (Show)
Published by christopherthielen over 6 years ago
Compare @uirouter/angular
versions 1.1.0 and 2.0.0
If using Angular v5, you should update to "rxjs": "^6.0.0"
and also add "rxjs-compat": "^6.0.0"
.
@uirouter/core
from 5.0.18 to 5.0.19Compare @uirouter/core
versions 5.0.18 and 5.0.19
Published by christopherthielen over 6 years ago
Compare @uirouter/angular
versions 1.0.1 and 1.1.0
@uirouter/core
from 5.0.17 to 5.0.18Compare @uirouter/core
versions 5.0.17 and 5.0.18
error()
to always return Rejection
(9bcc5db)Published by christopherthielen over 6 years ago
Compare @uirouter/angular
versions 1.0.0 and 1.0.1
@uirouter/core
from 5.0.16 to 5.0.17Compare @uirouter/core
versions 5.0.16 and 5.0.17
Published by christopherthielen over 6 years ago
Compare @uirouter/angular
versions 1.0.0-rc.3 and 1.0.0
@uirouter/core
from 5.0.14 to 5.0.16Compare @uirouter/core
versions 5.0.14 and 5.0.16
Compare @uirouter/angular
versions 1.0.0-rc.2 and 1.0.0-rc.3
@uirouter/core
from 5.0.13 to 5.0.14Compare @uirouter/core
versions 5.0.13 and 5.0.14
Compare @uirouter/angular
versions 1.0.0-rc.1 and 1.0.0-rc.2
@uirouter/core
from 5.0.11 to 5.0.13Compare @uirouter/core
versions 5.0.11 and 5.0.13
1.0.0-rc.0 (2017-11-15)
Compare @uirouter/angular
versions 1.0.0-beta.9 and 1.0.0-rc.0
Compare @uirouter/angular
versions 1.0.0-beta.8 and 1.0.0-beta.9
initial
property to forRoot
to specify the initial route. (b7b5e4f)@uirouter/core
from 5.0.10 to 5.0.11Compare @uirouter/core
versions 5.0.10 and 5.0.11
Compare @uirouter/angular
versions 1.0.0-beta.7 and 1.0.0-beta.8
@uirouter/core
updated from 5.0.4 to 5.0.10 (2017-10-07)Compare @uirouter/core
versions 5.0.4 and 5.0.10
self
instead of window
for webworker compat (a4629ee).value()
: returns value (WAIT) or promise (NOWAIT) (8769449)invokeLimit
to limit the number of times a hook is invoked before being auto-deregistered. (2cb17ef)views: { viewName: Component }
(84aec02)@uirouter/core
from 5.0.0 to 5.0.4
parent:
(828fe1b).value()
: returns value (WAIT) or promise (NOWAIT) (8769449)Published by christopherthielen over 7 years ago
The npm package changed to @uirouter/angular
. See UIRouter scoped packages for details
bindings:
work on a state declaration (as well as a view declaration) (a21c479)[@Input](https://github.com/Input)()
found. (4351c53)uiCanExit
hook for routed components (633573e)Previously, the ui-router-ng2
bundle included the code from ui-router-core
and ui-router-rx
.
Now, each UMD bundle must be included separately.
This change is most likely to affect:
This release of @uirouter/angular
updates @uirouter/core
from 4.0.0
to 5.0.0
.
Here are the changes from core:
State
object to StateObject
(feceaf9).register()
and StateMatcher.find()
misses (fdb3ab9)UrlRouter
) improve perf of registering Url Rules and sorting Url Rules (64fbfff)rules.initial("/home")
to config initial state (like otherwise) (bbe4209)State
object (now named StateObject
)import { State } from "ui-router-core";
const match = { to: (state: State) => state.data.auth };
transitionsvc.onEnter(match, (trans: Transition, state: State) => {
// state is the internal State object
if (state.includes["foo"]) { // internal ui-router API
return false;
}
}
import { StateDeclaration } from "ui-router-core";
const match = { to: (state: StateDeclaration) => state.data.auth };
transitionsvc.onEnter(match, (trans: Transition, state: StateDeclaration) => {
// state === the state object you registered
// Access internal ui-router API using $$state()
if (state.$$state().includes["foo"]) {
return false;
}
}
The State
object (now named StateObject
) is an internal API and should not be exposed via any public APIs.
If you depend on the internal APIs, you can still access the internal object by calling state.$$state()
.
How likely is this BC to affect me?
Medium: You will likely be affected you 1) have transition hooks, 2) are using typescript and/or 3) use the internal ui-router State API.
How severe is this BC?
Low: Access to the internal api is still available using $$state()
.
State
object to StateObject
import {State} from "ui-router-core";
import {StateObject} from "ui-router-core";
We'd like to use the State
name/symbol as a public API.
Some day (not today) it will likely be an ES7/TS decorator for ES6/TS state definition classes, i.e:
@State("foo")
export class FooState implements StateDeclaration {
url = "/foo";
component = FooComponent;
@Resolve({ deps: [FooService] })
fooData(fooService) {
return fooService.getFoos();
}
}
How likely is this to affect me?
Low: This only affects code that imports the internal API symbol State
.
You will likely be affected you 1) import that symbol, 2) are using typescript and 3) explicitly
typed a variable such as let internalStateObject = state.$$state();
How severe is this change?
Low: Find all places where State
is imported and rename to StateObject
Previously, if a transition hook returned a rejected promise:
.onStart({}, () => Promise.reject('reject transition'));
In onError
or transtion.promise.catch()
, the raw rejection was returned:
.onError({}, (trans, err) => err === 'reject transition')
Now, the error is wrapped in a Rejection object.
.detail
..onError({}, (trans, err) =>
err instanceof Rejection && err.detail === 'reject transition')
.type
of transition rejection (ABORTED, ERROR, SUPERSEDED and/or redirection)..onError({}, (trans, err) => {
err.type === RejectType.ABORTED === 3
});
Errors thrown from a hook and rejection values returned from a hook can now be processed in the same way.
How likely is this to affect me?
Medium: apps which have onError handlers for rejected values
How severe is this change?
Low: Find all error handlers (or .catch/.then chains) that do not understand Rejection. Add err.detail
processing.
onBefore
hooks are now run asynchronously like all the other hooks.Previously, the onBefore
hooks were run in the same stackframe as transitionTo
.
If they threw an error, it could be caught using try/catch.
transitionService.onBefore({ to: 'foo' }), () => { throw new Error('doh'); });
try {
stateService.go('foo');
} catch (error) {
// handle error
}
Now, onBefore
hooks are processed asynchronously.
To handle errors, use any of the async error handling paradigms:
transitionService.onBefore({ to: 'foo' }), () => { throw new Error('doh'); });
stateService.go('foo').catch(error => { //handle error });
transitionService.onBefore({ to: 'foo' }), () => { throw new Error('doh'); });
transitionService.onError({ to: 'foo' }), () => { // handle error });
stateService.go('foo');
transitionService.onBefore({ to: 'foo' }), () => { throw new Error('doh'); });
stateService.go('foo');
stateService.defaultErrorHandler(error => { // global error handler });
Why introduce a BC?
How likely is this to affect my app?
Very Low: Apps that registered onBefore hooks and depend on
synchronous execution are affected.
How severe is this BC?
Low: Switch to asynchronous handling, such as chaining off the
transition promise
defaultErrorHandler
Returning false
from a transition hook will abort the transition.
Previously, this case was considered an error and was logged by
defaultErrorHandler
.
After your feedback, we agree that this is not typically an error.
Now, aborted transitions do not trigger the defaultErrorHandler
Why introduce a BC?
Most users do not consider ABORT to be an error. The default error
handler should match this assumption.
How likely am I to be affected?
Low: Most users do not consider ABORT to be an error. For most users
this will not be a BC.
How severe is this BC?
Low: Users who want to handle all transition rejections can
register a .onError
handler and filter/process accordingly.
Published by christopherthielen over 7 years ago
This is a major release of ui-router-ng2
with many new features, including support for the angular-cli.
We now support AoT compilation with NgModule lazy loading (via Future States).
We also enabled code splitting support from the @ngtools/webpack
project.
There are numerous BREAKING CHANGES including those from the ui-router-core
dependency.
Please read through them carefully.
Commits eb5d599, 2a4b174, and 8088ef9 enable AoT compilation support and better Lazy Loading support.
When @ngtools/webpack
is being used, this also enables automatic code splitting + lazy loading.Â
Because angular-cli
uses @ngtools/webpack
, this change also enables angular-cli
support.
To use these new features, define a Future State
(by appending .**
to
the state name). Give the state a loadChildren
property which points
to a nested NgModule that will be lazy loaded. Use the same syntax that
@ngtools/webpack
expects: <pathToModule>#<name of export>
.
export var futureFooState = {
 name: 'foo.**',
 url: '/foo',
 loadChildren: './foo/foo.module#FooModule'
};
...
 imports: [
   UIRouterModule.forRoot({ states: [ futureFooState ] }),
...
In your nested module, add a state named foo
(without the .**
). This
nested module's foo
state will replace the foo.**
Future State (placeholder).
export var fooState = {
 name: 'foo',
 url: '/foo',
 resolve: {
   fooData: fooResolveFn
 },
 onEnter: onEnterFooFn,
 data: {
   requiresAuth: true
 }
};
...
 imports: [
   UIRouterModule.forChild({ states: [ fooState ] }),
...
This change works by providing the same DI token as the @angular/router
which is then analyzed for lazy loading by @ngtools/webpack
.
The ROUTES
token is deep imported from @angular/router/src/router_config_loader
.
The module's states are provided on the ROUTES token, which enables the
webpack tooling to analyze the states, looking for loadChildren
.
When the UMD bundle is built, the ROUTES token is pulled in from
@angular/router
(and duplicated), but should not be used by anything.
Because we pull in the token from the @angular/router
package, we have
a temporary dependency on the angular router. This is a temporary hack
until the @ngtools/webpack
project makes itself router-agnostic.
vanilla.*
from ui-router-core
(19113ee)UIRouterConfig
class. Now you use a function that receives the UIRouter
and the Injector
(9aae71a)loadChildren:
sugar on a state definition (2a4b174)__esModule
) (allows easier default export of NgModule) (2a4b174)This brings ui-router-ng2 npm package in line with how the core Angular 2 packages are packaged.
We compile and distribute esm+es5 + typescript typings in lib/
(formerly in lib-esm/
)
We no longer include the commonjs+es5 (formerly in lib/
)
We now point the main:
entry to the UMD bundle for commonjs users.
UIRouterConfig
class. Now you use a function that receives the UIRouter
and the Injector
In 1.0.0-beta.3 you might have a config class like this:
export class MyUIRouterConfig {
constructor(@Inject(UIRouter) router: UIRouter, @Inject(SomeService) myService: SomeService) {
// do something with router and injected service
}
}
which was wired into the root module like this:
```js
@NgModule({
imports: [
UIRouterModule.forRoot({ configClass: MyUIRouterConfig })
]
})
export class AppModule {}
In 1.0.0-beta.4 you should switch to a simple function.
The function receives the router: UIRouter
and injector: Injector
export function configureModule(router: UIRouter, injector: Injector) {
// do something with router
router.urlService.rules.type('slug', slugParamType);
// inject other services
const myService: SomeService = injector.get(SomeService);
// do something injected service
myService.init();
}
which is now wired using config: configureModule
instead of configClass: ...
@NgModule({
imports: [
UIRouterModule.forRoot({ configClass: MyUIRouterConfig })
]
})
export class AppModule {}
This 1.0.0-beta.4
release of ui-router-ng2
updates ui-router-core
from 1.0.0-beta.3
to 4.0.0
lazyLoad
stateBuilder: Get lazyLoad fn from internal State object, not StateDeclaration (9313880)State.lazyLoad
type def (9313880)params: { foo: { raw: true } }
overrides ParamType.raw
(aefeabf)int
param type is()
check (aa551e4), closes #3197
onBefore
hooks to cause infinite redirect loops (5c5f7eb), closes #6
redirectTo
(2c059c4)$state$
(a06948b)name()
return type to String
(a02f4a7)onFinish
(cc85e76)location
and locationConfig
from services
to UIRouter.locationService
and UIRouter.locationConfig
. (029fb00)string
parameter type no longer encodes slashes as ~2F
nor tildes as ~~
(72bb2d8)string
param type (72bb2d8)throw "Error 123"
), use .detail
, i.e.: (f486ced)html5Mode
and hashPrefix
from LocationServices
to LocationConfig
interface (9d316a7)ViewService.viewConfigFactory
and rootContext
to _pluginapi.*
(65badf4)lazyLoad
function was considered a future state. (ec50da4)getResolveValue
and getResolvable
methods from Transition
in favor of injector().get()
and injector().getAsync()
(111d259)LocationServices.setUrl
with LocationServices.url
(4c39dcb)ui-router-core
(f3392d1).**
name suffix (i.e., foo.**
) are considered future states (ec50da4)UIRouterGlobals
interface. Renamed Globals
class to UIRouterGlobals
(8719334)'#'
) to inherit: false
so it is cleared out when another transition occurs. (849f84f), closes #3245 #3218 #3017
StateService.lazyLoad
method to imperatively lazy load a state (ec50da4), closes #8
lazyLoadState
function (ec50da4)lazyLoad
hook can be used to lazy load anything (component code, etc) (ec50da4), closes #4
parts()
method which returns the URL parts as an object (32e64f0)path
and query
param types (72bb2d8)inherit: false
specified per parameter or type (849f84f)onEnter
(0dc2c19)injector()
to retrieve resolves for the exiting states/path (df502e8)ResolvableLiteral
in Transition.addResolvable
(ad9ae81)trace
global to the UIRouter
object (48c5af6)match()
: given a URL, return the best matching Url Rule (32e64f0)viewname@.
(normalizeUIViewTarget) (7078216), closes #25
This change will likely only affect a small subset of typescript users and probably only those using ui-router-ng2
.
If you're injecting the Globals
class somewhere, e.g.:
@Injectable()
class MyService {
_globals: UIRouterGlobals;
constructor(globals: Globals) {
this._globals = <UIRouterGlobals> globals;
}
}
you should now inject UIRouterGlobals
, e.g.:
@Injectable()
class MyService {
constructor(public globals: UIRouterGlobals) { }
}
Likewise, if you were casting the UIRouter.globals
object as a UIRouterGlobals
, it is no longer necessary:
function myHook(trans: Transition) {
let globals: UIRouterGlobals = trans.router.globals; // cast is no longer necessary
}
Closes https://github.com/ui-router/core/issues/31
throw "Error 123"
), use .detail
, i.e.:$state.go('foo').catch(err => { if (err === "Error 123") .. });
$state.go('foo').catch(err => { if (err.detail === "Error 123") .. });
URL Rules can come from registered states' .url
s, calling .when()
, or calling .rule()
.
It's possible that two or more URL Rules could match the URL.
Previously, url rules were matched in the order in which they were registered.
The rule which was registered first would handle the URL change.
Now, the URL rules are sorted according to a sort function.
More specific rules are preferred over less specific rules
It's possible to have multiple url rules that match a given URL.
Consider the following states:
{ name: 'books', url: '/books/index' }''
{ name: 'book', url: '/books/:bookId' }''
Both states match when the url is /books/index
.
Additionally, you might have some custom url rewrite rules such as:
.when('/books/list', '/books/index')
.
The book
state also matches when the rewrite rule is matched.
Previously, we simply used the first rule that matched. However, now that lazy loading is officially supported, it can be difficult for developers to ensure the rules are registered in the right order.
Instead, we now prioritize url rules by how specific they are. More specific rules are matched earlier than less specific rules.
We split the path on /
. A static segment (such as index
in the example) is more specific than a parameter (such as:bookId
).
The built-in rule sorting function (see UrlRouter.defaultRuleSortFn
) sorts rules in this order:
.when('/foo', '/bar', { priority: 1 })
(default priority is 0).when(string, ...)
).when(regexp, ...)
).rule()
)UrlMatcher.compare
)For complete control, a custom sort function can be registered with UrlService.rules.sort(sortFn)
Because query parameters are optional, they are not considered during sorting.
For example, both these rules will match when the url is '/foo/bar'
:
.when('/foo/bar', doSomething);
.when('/foo/bar?queryparam', doSomethingElse);
To choose the most specific rule, we match both rules, then choose the rule with the "best ratio" of matched optional parameters (see UrlRuleFactory.fromUrlMatcher
)
This allows child states to be defined with only query params for a URL.
The state only activates when the query parameter is present.
.state('parent', { url: '/parent' });
.state('parent.child', { url: '?queryParam' });
For backwards compatibility, register a sort function which sorts by the registration order:
myApp.config(function ($urlServiceProvider) {
function sortByRegistrationOrder(a, b) {
return a.$id - b.$id;
}
$urlServiceProvider.rules.sort(sortByRegistrationOrder);
});
LocationServices.setUrl
with LocationServices.url
This makes url()
a getter/setter. It also adds the optional state
parameter to pass through to the browser history when using pushstate.
End users should not notice this change, but plugin authors may.
The configuration functions from the provider object have been integrated into the normal UrlRouter object.
The UIRouter
object no longer has a uriRouterProvider
, but the equivalent functions can be found on uiRouter
One difference between the old functions on urlRouterProvider
and the new ones on uriRouter
is that new functions do not accept injectable functions.
string
parameter type no longer encodes slashes as ~2F
nor tildes as ~~
Previously, the string
parameter type pre-encoded tilde chars (~
) as two tilde chars (~~
) and slashes (/
) as ~2F
.
Now, the string
parameter type does not pre-encode slashes nor tildes.
If you rely on the previous encoding, create a custom parameter type that implements the behavior:
urlMatcherFactory.type('tildes', {
encode: (val: any) =>
val != null ? val.toString().replace(/(~|\/)/g, m => ({ '~': '~~', '/': '~2F' }[m])) : val;
decode: (val: string) =>
val != null ? val.toString().replace(/(~~|~2F)/g, m => ({ '~~': '~', '~2F': '/' }[m])) : val;
pattern: /[^/]*/
});
getResolveValue
and getResolvable
methods from Transition
in favor of injector().get()
and injector().getAsync()
In beta.3, the Transition APIs: injector()
, getResolvable
, and getResolveValue
duplicated functionality.
Instead of:
trans.getResolveValue('myResolve');
use:
trans.injector().get('myResolve')
location
and locationConfig
from services
to UIRouter.locationService
and UIRouter.locationConfig
.The core services
object is a mutable object which each framework was monkey patching.
This change removes the requirement to monkey patch a global mutable object.
Instead, framework implementors should pass the LocationServices
and LocationConfig
implementations into the UIRouter
constructor.
End users who were accessing services.location
or services.locationConfig
should access these off the UIRouter
instance instead.
html5Mode
and hashPrefix
from LocationServices
to LocationConfig
interfaceViewService.viewConfigFactory
and rootContext
to _pluginapi.*
This BC happened in commit 6c42285
.**
, i.e., foo.bar.**
Previously, a state with a lazyLoad
function was considered a future state.
Now, a state whose name ends with .**
(i.e., a glob pattern which matches all children) is a future state.
.**
.Change your future states from:
{ name: 'future', url: '/future', lazyLoad: () => ... }
to:
{ name: 'future.**', url: '/future', lazyLoad: () => ... }
string
param typePreviously, if a url parameter's type was not specified (in either the path or query), it defaulted to the string
type.
Now, path parameters default to the new path
type and query parameters default to the new query
type.
Published by christopherthielen about 8 years ago