This repository has been archived by the owner on Dec 19, 2017. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 19
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
17 changed files
with
553 additions
and
608 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
# Bindings | ||
|
||
The router is supplied with several bindings to make your life a bit easier and your apps | ||
a bit more powerful. The three bindings correlate to the `path`, `state`, and `query` arguments | ||
of `ctx.update`. These bindings use that function behind the scenes, so it should come as no | ||
surprise that they support the same bubbling behavior, however you can [lock the context](#locking-to-a-context) | ||
if necessary. | ||
|
||
## Usage | ||
|
||
```html | ||
<div data-bind="path: '/user', state: { user: user }, query: { search: 'foo' }"></div> | ||
``` | ||
|
||
#### Locking to a Context | ||
|
||
In certain cases, the default route bubbling behavior may not be quite right, | ||
and in those cases you need to nudge the router in the right direction. You can accomplish | ||
that with `..`, `./`, `//` following idiomatic path modifiers. | ||
|
||
`..` forces the router to bubble to the parent router. These can be chained, i.e. `../../my-route`. | ||
|
||
`./` forces the router to evaluate the route at the current context. This can be used to force a | ||
404 route in a child router. | ||
|
||
`//` forces top-down traversal rather than bottom-up. For all intents and purposes this can be regarded | ||
as a "absolute path" prefix with respect to the base path. | ||
|
||
#### Styling | ||
|
||
For convenience, elements with path bindings that match the current route have the `active-path` class | ||
added. | ||
|
||
#### Special Notes | ||
|
||
##### Use Anchors | ||
|
||
While the bindings rely on the `click` binding so you can functionally attach them to any element you choose, | ||
if you wish to preserve ctrl+click, context menu (open in new tab/window, etc.), and other native browser UX | ||
you must still use anchor tags. The path binding will set an `href` property for these behaviors to fall back on. | ||
|
||
##### Passing Data | ||
|
||
It may not seem immediately intuitive, but the state binding can be quite handy for passing data around in apps | ||
without a full blown model/collection layer. Imagine the following situation. | ||
|
||
- A `user-list` component with a list of users | ||
- A `user-show` component that lists individual user information | ||
|
||
If this data lives on a server it makes sense you would want to avoid having to refetch data. | ||
Assuming the `user-list` viewmodel loads an array of `user` objects with the same schema the | ||
`user-show` component uses to render, one way to do this could be to add the following binding | ||
the anchor tags in the `user-list` component... | ||
|
||
```html | ||
<!-- ko foreach: { data: users, as: 'user' } --> | ||
<a data-bind="path: '/users/' + user.id, state: { user: user }, text: user.name"></a> | ||
<!-- /ko --> | ||
``` | ||
|
||
And the following in the `user-show` viewmodel... | ||
|
||
```javascript | ||
class ViewModel { | ||
constructor(ctx) { | ||
this.user = ctx.state().user | ||
} | ||
} | ||
``` | ||
|
||
##### Unit Testing | ||
|
||
The bindings expect to find a `$router` object containing the router on the binding context and will throw an | ||
error if it is not found. | ||
|
||
To remedy this you can stub the router with the files in the `lib` directory — these are the source | ||
files babel-ified and exported for commonjs, i.e. webpack/browserify/etc. | ||
|
||
Consult the following example... | ||
|
||
```javascript | ||
import ko from 'knockout' | ||
import RouterContext from 'ko-component-router/lib/context' | ||
// const RouterContext = require('ko-component-router/lib/context').default in a commonjs environment | ||
import 'ko-component-router/lib/binding' | ||
import { renderComponent } from 'ko-component-tester' | ||
import parentRouterRoutes from '../path/to/routes' | ||
import routes from './path/to/routes' | ||
|
||
// this assumes you are using webpack or a similar tool | ||
// to write your templates in HTML. Adjust accordingly. | ||
import template from './path/to/template.html' | ||
|
||
const parentRouter = new RouterContext({}, { routes: parentRouterRoutes, base: '/root' }) | ||
const $router = new RouterContext({ $parentContext: { $router: parentRouter } }, { routes }) | ||
|
||
describe('<app-nav/>', () => { | ||
const $el = renderComponent({ template }, { params }, { $router }) | ||
|
||
it('has home link', () => expect($el.find('a[href=/root/instructor]')).to.exist) | ||
}) | ||
``` | ||
|
||
Alternatively you could delete `path`, `state`, and `query` from `ko.bindingHandlers` before rendering. | ||
|
||
_Related:_ | ||
- [ko-component-tester#renderComponent](https://github.com/Profiscience/ko-component-tester#rendercomponentcomponent-params-bindingcontext) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
# Config | ||
|
||
These are the options available to pass to the `<ko-component-router></ko-component-router>` component | ||
|
||
## routes | ||
|
||
`routes` is an object where the keys are [express style](https://github.com/pillarjs/path-to-regexp) routes and | ||
values are the array `[...callbacks, 'component-name']` or just `component-name` for shorthand. `...callbacks` are | ||
functions that are called with the router context and an optional `done` callback and will be called sequentially | ||
before setting the router's view to `'component-name'`. If callbacks aren't your style, you can also use promises. | ||
|
||
```javascript | ||
const routes = { | ||
// explicit path | ||
'/about': 'about', | ||
|
||
// one required param (\`name\`) | ||
// one optional param (\`operation\`) | ||
'/user/:name/:operation?': [ | ||
getUser, | ||
'user' | ||
], | ||
|
||
// wildcard segment | ||
'/*': '404', | ||
|
||
// named wildcard segment | ||
'/file/:file(*)': 'file' | ||
} | ||
|
||
function getUser(ctx /*, done */) { | ||
return new Promise((resolve) => { | ||
$.get(`/API/Users/${ctx.params.name}`).then((u) => { | ||
ctx.state.user = u | ||
resolve() | ||
}) | ||
}) | ||
} | ||
``` | ||
|
||
The callbacks can also be used for dynamic routing by setting `ctx.route.component` | ||
|
||
```javascript | ||
const routes = { | ||
'/user/:name/:operation?': [getComponent] | ||
} | ||
|
||
function getComponent(ctx) { | ||
if (ctx.params.operation === 'edit') { | ||
ctx.route.component = 'user-edit' | ||
} else { | ||
ctx.route.component = 'user-show' | ||
} | ||
} | ||
``` | ||
|
||
## base | ||
|
||
The base path your app is running under, if applicable. | ||
e.g., your app is running from a \`/blog\` directory | ||
|
||
__This option is only applicable to the top-level router__ | ||
|
||
## hashbang | ||
|
||
Whether or not to use HTML4 hashbang routing. Defaults to false. | ||
|
||
When using with legacy browsers that do not support the <code>history</code> | ||
API, you should include the <a href="https://github.com/devote/HTML5-History-API">HTML5-History-API polyfill</a> | ||
with the following one-liner. | ||
|
||
```html | ||
<!--[if lte IE 9]><script src="https://cdnjs.cloudflare.com/ajax/libs/html5-history-api/4.0.2/history.iegte8.min.js?type=!/&basepath=<basepath>"></script><![endif]--> | ||
``` | ||
|
||
__This option is only applicable to the top-level router__ | ||
|
||
## persistQuery | ||
|
||
Whether or not to preserve the querystring when navigating between pages. Defaults to false. | ||
|
||
Note, when the router is unmounted the queries will be disposed. | ||
|
||
## persistState | ||
|
||
Whether or not to preserve the querystring when navigating between pages. defaults to false. | ||
|
||
Note, when the router is unmounted the states will be disposed. | ||
|
||
## inTransition: (el, fromCtx, toCtx) => {} | ||
|
||
Defines a function to run immediately after mounting a component | ||
|
||
## outTransition: (el, fromCtx, toCtx[, done]) => {} | ||
|
||
Defines a function to run immediately before unmounting a component |
Oops, something went wrong.