docs/api/dom.html
<!doctype html>
<html>
<head>
<meta charset='utf-8'>
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width">
<title>Cycle.js - API reference (dom)</title>
<!-- Flatdoc -->
<script src='../support/vendor/jquery.js'></script>
<script src='../support/vendor/highlight.pack.js'></script>
<script src='../legacy.js'></script>
<script src='../flatdoc.js'></script>
<!-- Algolia's DocSearch main theme -->
<link href='//cdn.jsdelivr.net/docsearch.js/2/docsearch.min.css' rel='stylesheet' />
<!-- Others -->
<script async src="//static.jsbin.com/js/embed.js"></script>
<!-- Flatdoc theme -->
<link href='../theme/style.css' rel='stylesheet'>
<script src='../theme/script.js'></script>
<link href='../support/vendor/highlight-github-gist.css' rel='stylesheet'>
<!-- Meta -->
<meta content="Cycle.js - API reference (dom)" property="og:title">
<meta content="A functional and reactive JavaScript framework for predictable code" name="description">
<!-- Content -->
<script id="markdown" type="text/markdown" src="index.html">
# Cycle DOM - [source](https://github.com/cyclejs/cyclejs/tree/master/dom)
A Cycle.js driver to enable interaction with the DOM. The driver is based on [snabbdom](https://github.com/paldepind/snabbdom/) as the Virtual DOM library.
```
npm install @cycle/dom
```
## Browser support
These are the browsers we officially test for:
- Chrome 49 and higher
- Firefox 52 and higher
- Safari 9.1 and higher
- Android Chrome (OS version 4.4 and higher)
- iOS Safari (OS version 10.3 and higher)
- Microsoft Edge
- Internet Explorer 11
**Note for Internet Explorer 10:** This driver works on IE10 only if you polyfill ES6 Map, ES6 Set, [MutationObserver](https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver) (we recommend `mutation-observer` package from npm) **and** if you don't render the app in a [DocumentFragment](https://developer.mozilla.org/en-US/docs/Web/API/DocumentFragment).
In other browsers, the DOM driver may not work or may work partially.
# Isolation semantics
Cycle DOM supports isolation between components using the `@cycle/isolate` package. Here is how isolation contexts work in Cycle DOM given a `scope` to `isolate(Component, scope)`:
**When the scope is the `':root'` string: no isolation.**
The child component will have run in the same context as its parent, and methods like `DOMSource.select()` will inspect the DOM trees of the parent. This means the child component is able to inspect DOM trees that it did not itself produce.
**When the scope is a selector string (e.g. '.foo' or '#foo'): siblings isolation.**
A `DOMSource.select()` call in a parent component will have access to the DOM trees in both children isolated with "siblings isolation" (which means there is no parent-child isolation). However, a `DOMSource.select()` inside a child component isolated with "siblings isolation" will have no access to the DOM trees in other children components isolated with "siblings isolation".
**When the scope is any other string: total isolation.**
A `DOMSource.select()` call in a parent component will have no access to the DOM trees in a totally isolated child. Also, sibling components will have no access to the DOM trees in a totally isolated sibling component.
# API
## <a id="makeDOMDriver"></a> `makeDOMDriver(container, options)`
A factory for the DOM driver function.
Takes a `container` to define the target on the existing DOM which this
driver will operate on, and an `options` object as the second argument. The
input to this driver is a stream of virtual DOM objects, or in other words,
Snabbdom "VNode" objects. The output of this driver is a "DOMSource": a
collection of Observables queried with the methods `select()` and `events()`.
**`DOMSource.select(selector)`** returns a new DOMSource with scope
restricted to the element(s) that matches the CSS `selector` given. To select
the page's `document`, use `.select('document')`. To select the container
element for this app, use `.select(':root')`.
**`DOMSource.events(eventType, options)`** returns a stream of events of
`eventType` happening on the elements that match the current DOMSource. The
event object contains the `ownerTarget` property that behaves exactly like
`currentTarget`. The reason for this is that some browsers doesn't allow
`currentTarget` property to be mutated, hence a new property is created. The
returned stream is an *xstream* Stream if you use `@cycle/xstream-run` to run
your app with this driver, or it is an RxJS Observable if you use
`@cycle/rxjs-run`, and so forth.
**options for DOMSource.events**
The `options` parameter on `DOMSource.events(eventType, options)` is an
(optional) object with two optional fields: `useCapture` and
`preventDefault`.
`useCapture` is by default `false`, except it is `true` for event types that
do not bubble. Read more here
https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener
about the `useCapture` and its purpose.
`preventDefault` is by default `false`, and indicates to the driver whether
`event.preventDefault()` should be invoked. This option can be configured in
three ways:
- `{preventDefault: boolean}` to invoke preventDefault if `true`, and not
invoke otherwise.
- `{preventDefault: (ev: Event) => boolean}` for conditional invocation.
- `{preventDefault: NestedObject}` uses an object to be recursively compared
to the `Event` object. `preventDefault` is invoked when all properties on the
nested object match with the properties on the event object.
Here are some examples:
```typescript
// always prevent default
DOMSource.select('input').events('keydown', {
preventDefault: true
})
// prevent default only when `ENTER` is pressed
DOMSource.select('input').events('keydown', {
preventDefault: e => e.keyCode === 13
})
// prevent defualt when `ENTER` is pressed AND target.value is 'HELLO'
DOMSource.select('input').events('keydown', {
preventDefault: { keyCode: 13, ownerTarget: { value: 'HELLO' } }
});
```
**`DOMSource.elements()`** returns a stream of arrays containing the DOM
elements that match the selectors in the DOMSource (e.g. from previous
`select(x)` calls).
**`DOMSource.element()`** returns a stream of DOM elements. Notice that this
is the singular version of `.elements()`, so the stream will emit an element,
not an array. If there is no element that matches the selected DOMSource,
then the returned stream will not emit anything.
#### Arguments:
- `container: String|HTMLElement` the DOM selector for the element (or the element itself) to contain the rendering of the VTrees.
- `options: DOMDriverOptions` an object with two optional properties:
- `modules: array` overrides `@cycle/dom`'s default Snabbdom modules as
as defined in [`src/modules.ts`](./src/modules.ts).
- `reportSnabbdomError: (err: any) => void` overrides the default error reporter function.
#### Returns:
*(Function)* the DOM driver function. The function expects a stream of VNode as input, and outputs the DOMSource object.
## <a id="mockDOMSource"></a> `mockDOMSource(mockConfig)`
A factory function to create mocked DOMSource objects, for testing purposes.
Takes a `mockConfig` object as argument, and returns
a DOMSource that can be given to any Cycle.js app that expects a DOMSource in
the sources, for testing.
The `mockConfig` parameter is an object specifying selectors, eventTypes and
their streams. Example:
```js
const domSource = mockDOMSource({
'.foo': {
'click': xs.of({target: {}}),
'mouseover': xs.of({target: {}}),
},
'.bar': {
'scroll': xs.of({target: {}}),
elements: xs.of({tagName: 'div'}),
}
});
// Usage
const click$ = domSource.select('.foo').events('click');
const element$ = domSource.select('.bar').elements();
```
The mocked DOM Source supports isolation. It has the functions `isolateSink`
and `isolateSource` attached to it, and performs simple isolation using
classNames. *isolateSink* with scope `foo` will append the class `___foo` to
the stream of virtual DOM nodes, and *isolateSource* with scope `foo` will
perform a conventional `mockedDOMSource.select('.__foo')` call.
#### Arguments:
- `mockConfig: Object` an object where keys are selector strings and values are objects. Those nested objects have `eventType` strings as keys
and values are streams you created.
#### Returns:
*(Object)* fake DOM source object, with an API containing `select()` and `events()` and `elements()` which can be used just like the DOM Driver's
DOMSource.
## <a id="h"></a> `h()`
The hyperscript function `h()` is a function to create virtual DOM objects,
also known as VNodes. Call
```js
h('div.myClass', {style: {color: 'red'}}, [])
```
to create a VNode that represents a `DIV` element with className `myClass`,
styled with red color, and no children because the `[]` array was passed. The
API is `h(tagOrSelector, optionalData, optionalChildrenOrText)`.
However, usually you should use "hyperscript helpers", which are shortcut
functions based on hyperscript. There is one hyperscript helper function for
each DOM tagName, such as `h1()`, `h2()`, `div()`, `span()`, `label()`,
`input()`. For instance, the previous example could have been written
as:
```js
div('.myClass', {style: {color: 'red'}}, [])
```
There are also SVG helper functions, which apply the appropriate SVG
namespace to the resulting elements. `svg()` function creates the top-most
SVG element, and `svg.g`, `svg.polygon`, `svg.circle`, `svg.path` are for
SVG-specific child elements. Example:
```js
svg({attrs: {width: 150, height: 150}}, [
svg.polygon({
attrs: {
class: 'triangle',
points: '20 0 20 150 150 20'
}
})
])
```
</script>
<!-- Initializer -->
<script>
Flatdoc.run({
fetcher: function (callback) {
callback(null, document.getElementById('markdown').innerHTML);
},
highlight: function (code, value) {
return hljs.highlight(value, code).value;
},
});
</script>
</head>
<body role='flatdoc' class="no-literate">
<div class='header'>
<div class='left'>
<h1><a href="/"><img class="logo" src="../img/cyclejs_logo.svg">Cycle.js</a></h1>
<ul>
<li><a href='../getting-started.html'>Guide</a></li>
<li><a href='../api/index.html'>API</a></li>
<li><a href='../releases.html'>Releases</a></li>
<li><a href='https://github.com/cyclejs/cyclejs'>GitHub</a></li>
</ul>
<input id="docsearch" />
</div>
<div class='right'>
<!-- GitHub buttons: see https://ghbtns.com -->
<iframe src="https://ghbtns.com/github-btn.html?user=cyclejs&repo=cyclejs&type=watch&count=true"
allowtransparency="true" frameborder="0" scrolling="0" width="110" height="20"></iframe>
</div>
</div>
<div class='content-root'>
<div class='menubar'>
<div class='menu section'>
<div role='flatdoc-menu'></div>
</div>
</div>
<div role='flatdoc-content' class='content'></div>
</div>
<script>
((window.gitter = {}).chat = {}).options = {
room: 'cyclejs/cyclejs'
};
</script>
<script src="https://sidecar.gitter.im/dist/sidecar.v1.js" async defer></script>
<script src='//cdn.jsdelivr.net/docsearch.js/2/docsearch.min.js'></script>
<script src='../docsearch.js'></script>
</body>
</html>