Skip to content

Commit

Permalink
feat(ui-router-ng2): Update providers and viewsBuilder to match new 1…
Browse files Browse the repository at this point in the history
….0 API
  • Loading branch information
christopherthielen committed Apr 1, 2016
1 parent d42b617 commit ff54d61
Show file tree
Hide file tree
Showing 9 changed files with 383 additions and 12 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
},
"license": "MIT",
"devDependencies": {
"angular2": "^2.0.0-beta.1",
"angular2": "^2.0.0-beta.12",
"babel-core": "^5.8.14",
"conventional-changelog": "^1.1.0",
"conventional-changelog-cli": "^1.1.1",
Expand Down
6 changes: 2 additions & 4 deletions src/ng2.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,8 @@
/** for typedoc */

export * from "./core";

import "./justjs";

export * from "./ng2/uiView";
export * from "./ng2/uiSref";
export * from "./ng2/uiSrefActive";
export * from "./ng2/providers";
export * from "./ng2/directives";

9 changes: 9 additions & 0 deletions src/ng2/directives.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@

import {UiSref} from "../ng2/uiSref";
import {UiSrefClass} from "../ng2/uiSrefActive";
import {UiView} from "../ng2/uiView";
export * from "./uiSref";
export * from "./uiSrefActive";
export * from "./uiView";

export let UIROUTER_DIRECTIVES = [UiSref, UiSrefClass, UiView];
300 changes: 297 additions & 3 deletions src/ng2/interface.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,301 @@
/** @module ng2 */ /** */
import {_ViewDeclaration} from "../state/interface";
import {StateDeclaration, _ViewDeclaration} from "../state/interface";
import {ParamDeclaration} from "../params/interface";
import {IInjectable} from "../common/common";
import {Transition} from "../transition/transition";
import {Type} from "angular2/core";

/**
* The StateDeclaration object is used to define a state or nested state.
* It should be registered with the [[StateRegistry]].
*
* @example
* ```js
*
* import {FoldersComponent} from "./folders";
*
* // StateDeclaration object
* var foldersState = {
* name: 'folders',
* url: '/folders',
* component: FoldersComponent,
* resolve: {
* allfolders: function(FolderService) {
* return FolderService.list();
* }
* }
* }
* ```
*/
export interface Ng2StateDeclaration extends StateDeclaration, Ng2ViewDeclaration {
/**
* An optional object used to define multiple named views.
*
* Each key is the name of a view, and each value is a [[Ng2ViewDeclaration]].
* Unnamed views are internally renamed to `$default`.
*
* A view's name is used to match an active `<ui-view>` directive in the DOM. When the state
* is entered, the state's views are activated and then matched with active `<ui-view>` directives:
*
* - The view's name is processed into a ui-view target:
* - ui-view address: an address to a ui-view
* - state anchor: the state to anchor the address to
*
* Examples:
*
* Targets three named ui-views in the parent state's template
*
* @example
* ```js
*
* views: {
* header: HeaderComponent,
* body: BodyComponent,
* footer: FooterComponent
* }
* ```
*
* @example
* ```js
*
* // Targets named ui-view="header" in the template of the ancestor state 'top'
* // and the named `ui-view="body" from the parent state's template.
* views: {
* 'header@top': MsgHeaderComponent,
* 'body': MessagesComponent
* }
* ```
*
* ## View targeting details
*
* There are a few styles of view addressing/targeting. The most common is a simple `ui-view` name
*
*
* #### Simple ui-view name
*
* Addresses without an `@` are anchored to the parent state.
*
* @example
* ```js
*
* // target the `<div ui-view='foo'></div>` created in the parent state's view
* views: { foo: {...} }
* ```
*
* #### View name anchored to a state
*
* You can anchor the `ui-view` name to a specific state by including an `@`
*
* @example
*
* ```js
*
* // target the `<div ui-view='foo'></div>` which was created in a
* // view owned by the state `bar.baz`
* views: { 'foo@bar.baz': {...} }
* ```
*
* #### Absolute addressing
*
* You can address a `ui-view` absolutely, using dotted notation, by prefixing the address with a `!`. Dotted
* addresses map to the hierarchy of `ui-view`s active in the DOM:
*
* @example
* ```js
*
* // absolutely target the `<div ui-view='nested'></div>`... which was created
* // in the unnamed/$default root `<ui-view></ui-view>`
* views: { '!$default.nested': {...} }
* ```
*
* #### Relative addressing
*
* Absolute addressing is actually relative addressing, only anchored to the unnamed root state. You can also use
* relative addressing anchored to any state, in order to target a target deeply nested `ui-views`:
*
* @example
* ```js
*
*
* // target the `<div ui-view='bar'></div>`... which was created inside the
* // `<div ui-view='bar'></div>`... which was created inside the parent state's template.
* views: { 'foo.bar': {...} }
* ```
*
* @example
* ```js
*
* // target the `<div ui-view='bar'></div>`... which was created in
* // `<div ui-view='foo'></div>`... which was created in a template crom the state `baz.qux`
* views: { 'foo.bar@baz.qux': {...} }
*
* ---
*
* ## State `component:` and `views:` incompatiblity
*
* If a state has a `views` object, the state-level `component:` property is ignored. Therefore,
* if _any view_ for a state is declared in the `views` object, then _all of the state's views_ must be defined in
* the `views` object.
*/
views?: { [key: string]: Ng2ViewDeclaration; };
}

export interface Ng2ViewDeclaration extends _ViewDeclaration {
component: Type;
}
/**
* The class of the `Component` to use for this view.
*
* A property of [[Ng2StateDeclaration]] or [[Ng2ViewDeclaration]]:
*
* The component class which will be used for this view.
*
* Resolve data can be provided to the component using Dependency Injection. Currently, resolves must be injected
* into the component using `@Inject('key')`, where `key` is the name of the resolve.
*
* TODO: document ng2 shorthand, like ng1's shorthand: inside a "views:" block, a bare string `"foo"` is shorthand for `{ component: "foo" }`
*
* @example
* ```js
*
* .state('profile', {
* // Use the <my-profile></my-profile> component for the Unnamed view
* component: MyProfileComponent,
* }
*
* .state('messages', {
* // use the <nav-bar></nav-bar> component for the view named 'header'
* // use the <message-list></message-list> component for the view named 'content'
* views: {
* header: { component: NavBar },
* content: { component: MessageList }
* }
* }
*
* .state('contacts', {
* // Inside a "views:" block, supplying only a Component class is shorthand for { component: NavBar }
* // use the <nav-bar></nav-bar> component for the view named 'header'
* // use the <contact-list></contact-list> component for the view named 'content'
* views: {
* header: NavBar,
* content: ContactList
* }
* }
* ```
*/
component?: Type;

/**
* @hidden
*
* An object which maps `resolve`s to [[component]] `bindings`.
*
* A property of [[Ng2StateDeclaration]] or [[Ng2ViewDeclaration]]:
*
* When using a [[component]] declaration (`component: 'myComponent'`), each input binding for the component is supplied
* data from a resolve of the same name, by default. You may supply data from a different resolve name by mapping it here.
*
* Each key in this object is the name of one of the component's input bindings.
* Each value is the name of the resolve that should be provided to that binding.
*
* Any component bindings that are omitted from this map get the default behavior of mapping to a resolve of the
* same name.
*
* @example
* ```js
*
* $stateProvider.state('foo', {
* resolve: {
* foo: function(FooService) { return FooService.get(); },
* bar: function(BarService) { return BarService.get(); }
* },
* component: 'Baz',
* // The component's `baz` binding gets data from the `bar` resolve
* // The component's `foo` binding gets data from the `foo` resolve (default behavior)
* bindings: {
* baz: 'bar'
* }
* });
*
* app.component('Baz', {
* templateUrl: 'baz.html',
* controller: 'BazController',
* bindings: {
* foo: '<', // foo binding
* baz: '<' // baz binding
* }
* });
* ```
*
*/
// bindings?: { [key: string]: string };
}

/**
* The shape of a controller for a view (and/or component), defining the controller callbacks.
*
* A view in UI-Router is comprised of either a `component` ([[Ng2ViewDeclaration.component]]) or a combination of a
* `template` (or `templateProvider`) and a `controller` (or `controllerProvider`).
*
* The `controller` object (or the `component`'s controller object) can define component-level controller callbacks,
* which UI-Router will call at the appropriate times. These callbacks are similar to Transition Hooks
* ([[IHookRegistry]]), but are only called if the view is currently active.
*
* This interface defines the UI-Router component callbacks.
*
* TODO: this should extend the ng2 Component interface
*/
export interface Ng2Component {
/**
* This callback is called when parameter values have changed.
*
* This callback can be used to respond to changing parameter values in the current state, or in parent/child states.
* This callback is especially handy when using dynamic parameters ([[ParamDeclaration.dynamic]])
*
* Called when:
* - The view is still active
* - A new transition has completed successfully
* - The state for the view (controller) was not reloaded
* - At least one parameter value was changed
*
* Called with:
* @param newValues an object containing the changed parameter values
* @param $transition$ the new Transition which triggered this callback
*
* @example:
* ```js
*
* angular.module('foo').controller('FancyCtrl', function() {
* this.uiOnParamsChanged = function(newParams) {
* console.log("new params: ", newParams);
* }
* });
* ```
*/
uiOnParamsChanged(newValues: any, $transition$: Transition);

/**
* This callback is called when the view's state is about to be exited.
*
* This callback is used to inform a view that it is about to be exited, due to a new [[Transition]].
* The callback can ask for user confirmation, and cancel or alter the new Transition. The callback should
* return a value, or a promise for a value. If a promise is returned, the new Transition waits until the
* promise settles.
*
*
* Called when:
* - The view is still active
* - A new Transition is about to run
* - The new Transition will exit the view's state
*
* Called with:
* - This callback is injected in the new Transition's context
*
* Relevant return Values:
* - `false`: The transition is cancelled.
* - A rejected promise: The transition is cancelled.
* - [[TargetState]]: The transition is redirected to the new target state.
* - Anything else: the transition will continue normally (the state and view will be deactivated)
*
* @return a value, or a promise for a value.
*/
uiCanExit();
}
43 changes: 43 additions & 0 deletions src/ng2/providers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import {Provider, provide} from "angular2/core";
import {UIRouter} from "../router";
import {Node} from "../path/node";
import {StateRegistry} from "../state/stateRegistry";
import {StateService} from "../state/stateService";
import {TransitionService} from "../transition/transitionService";
import {UrlMatcherFactory} from "../url/urlMatcherFactory";
import {UrlRouter} from "../url/urlRouter";
import {ViewService} from "../view/view";
import {UiView} from "./uiView";
import {ng2ViewsBuilder, Ng2ViewConfig} from "./viewsBuilder";
import {Ng2ViewDeclaration} from "./interface";

export const UIROUTER_PROVIDERS: Provider[] = [

provide(UIRouter, { useFactory: () => {
let router = new UIRouter();

router.viewService.viewConfigFactory("ng2", (node: Node, config: Ng2ViewDeclaration) => new Ng2ViewConfig(node, config));
router.stateRegistry.decorator('views', ng2ViewsBuilder);
router.stateRegistry.stateQueue.autoFlush(router.stateService);

return router;
} }),

provide(StateService, { useFactory: (r: UIRouter) => { return r.stateService; }, deps: [UIRouter]}),

provide(TransitionService, { useFactory: (r: UIRouter) => { return r.transitionService; }, deps: [UIRouter]}),

provide(UrlMatcherFactory, { useFactory: (r: UIRouter) => { return r.urlMatcherFactory; }, deps: [UIRouter]}),

provide(UrlRouter, { useFactory: (r: UIRouter) => { return r.urlRouter; }, deps: [UIRouter]}),

provide(ViewService, { useFactory: (r: UIRouter) => { return r.viewService; }, deps: [UIRouter]}),

provide(StateRegistry, { useFactory: (r: UIRouter) => { return r.stateRegistry; }, deps: [UIRouter]}),

provide(UiView.INJECT.context, { useFactory: (r: StateRegistry) => { console.log(r); return r.root(); }, deps: [StateRegistry]} ),

provide(UiView.INJECT.fqn, { useValue: null })

];

Loading

0 comments on commit ff54d61

Please sign in to comment.