This library provides js-virtual-dom based renderering to coconut.
Once you have a view, you can render it in the DOM using parent.appendChild(theView.toElement()). Simples.
Every view "owns" the js.html.Element that it last rendered to. Note that the element may have to be swapped, e.g. if its type changes, e.g. imagine the following:
class Button extends coconut.ui.View<{ onclick:Void->Void, disabled:Bool, label:String }> {
function render() '
<if {disabled}>
<span>{label}</span>
<else>
<button onclick={onclick}>{label}</button>
</if>
'
}Disregarding the fact that this is would make for a hot contender in a competition for finding the stupidest way to render buttons, it's important to understand that if you create an enabled button and then disable it, the span is replaced by a button in the actual dom. Performance wise this may have quite far reaching implications. It is therefore suggested to always wrap your views, e.g.:
class Button extends coconut.ui.View<{ onclick:Void->Void, disabled:Bool, label:String }> {
function render() '
<div class="button">
<if {disabled}>
<span>{label}</span>
<else>
<button onclick={onclick}>{label}</button>
</if>
</div>
';
}That said, you should never rely on a views element staying the same, certainly not from outside the view, but also not from the inside.
Every view has the following life cycle hooks that you may override:
function beforeInit():Void;
function afterInit(element:Element):Void;
function beforePatching(element:Element):Void;
function afterPatching(element:Element):Void;
function beforeDestroy(element:Element):Void;
function afterDestroy(element:Element):Void;Views are initialized in two cases:
- You call their
toElementmethod. - When they are rendered for the first time by a parent view.
Once a view is initialized, it begins to observe the data it is meant to render. Should that data change, a rerender is scheduled. Rerendering entails:
- Rendering the new data as VDOM and calculating the diff from the previous render.
- Calling
beforePatchwith the current DOM element. - Applying the patch.
- Calling
afterPatchwith the updated DOM element.
Note that changes to the DOM may lead to the strangest effects. Perform them at your own risk. The before/after patching methods are primarily meant for dealing with scroll position, focus and similar state that is not reflected in the DOM structure directly.
Event handling in coconut.vdom is fully typed, meaning that the event type and the event target are what you'd actually expect them to be:
class Input extends View<{ value:String, onchange:String->Void }>{
function render() '
<input type="text" value={value} onchange={onchange(event.target.value)} />
';
}Here's the shortlist of things to keep in mind:
- A view's element may change during its life cycle
- A view may be replaced by an otherwise completely equal view