Table of Contents
Web Reactive Programming
Hop.js Web Reactive Programming (WRP) enables DOM nodes components to be automatically updated or modified to reflect modifications of the program manipulated data. The components might be nodes attributes, nodes themselves that be can be modified or replaced, or even new nodes that can be added.
WRP ressorts on two components: the sources and the sinks. The sources are surpervised data structures whose modification yield to DOM updates. The sinks are the DOM components that are updated when sinks changes. They might be DOM nodes attributes and DOM nodes themselves.
Here is a first example, inspired by a React.js example that creates
a web page showing the chronometers. The source is the state
variable.
The sink is the react
node. The modification of the state
variables
that occur each seconds automatically yield to updating the web
page.
stateful.js
service stateful() {
return <html>
~{
var state = hop.reactProxy( { secondsElapsed: 0 } );
setInterval( function() { state.secondsElapsed++; }, 1000 );
}
<div>Seconds Elapsed: <react>~{ state.secondsElapsed }</react></div>
</html>
}
A second example, also inspired by the React.js web site:
app.js
function TODOLIST( attrs, body ) {
return <ul>
<react>~{${attrs.items}.map( createItem )}</react>
</ul>;
}
service todolist() {
return <html>
~{
function handleSubmit( e ) {
e.preventDefault();
state.items.push( { text: state.text, id: Date.now() } );
}
function onChange( e ) {
state.text = e.target.value;
}
function createItem( item ) {
return <li key=${item.id}> ${item.text} </li>;
}
var state = ( { items: new hop.reactProxy( [] ), text: '' } );
}
<div>
<h3>TODO</h3>
<TodoList items=~{state.items}/>
<form onSubmit=~{handleSubmit( event )}>
<input onchange=~{onChange( event )}/>
<button>Add #<react>~{state.items.length + 1}</react></button>
</form>
</div>
</html>
}
The third example, inspired by the Stratisfied Js web site:
ui.js
service ui() {
return <html>
~{
var R = hop.reactProxy( { min: 0, max: 100 } );
var mid;
}
<body>
<react> ~{
if( R.min == R.max ) {
return <div>Got it: ${R.min}!
<button onclick=~{R.min = 0; R.max = 100}>again</button>
</div>
} else if( R.min == 0 ) {
return <div>Think of an integer between ${R.min + 1} and ${R.max}
<button onclick=~{
R.min = 1; R.max = 100;
}>Ok
</button>
</div>
} else {
mid = R.min + Math.round((R.max-R.min)/2);
return <div>Is it smaller than ${mid}?
<button onclick=~{R.max = mid - 1 }>Yes</button>
<button onclick=~{R.min = mid }>No</button>
</div>
}
}
</react>
</body>
</html>
}
Methods
Sources are implemented a subclass of the JavaScript proxy objects.
As such only allocated objects can be used as sources, by opposition
to numbers, booleans, undefined
, null
, or literal strings.
hop.reactProxy( object )
The hop.reactProxy
method creates a reactive source out of
object
. Each modification to object
will yield to updating the
DOM nodes that depends on that object.
server.reactProxy( event, value )
The server.reactproxy
method creates a reactive source out of
a server event. Each time event
is receive, the DOM is updated
accordingly. The default value
is used until event
is received.
reactsrv/reactsrv.js
var clients = [];
service reactsrv() {
clients.push( clients.length + ": " + Date() );
hop.broadcast( "clients", clients );
return <html>
~{ var conn = server.reactProxy( "clients", [] ); }
<div># clients:
<ol>
<react>~{ conn.value.map( function( c ) {
return <li>${c}</li>
} ) }
</react>
</ol>
</div>
</html>
}
console.log( "Go to \"http://%s:%d/hop/reactsrv\"", hop.hostname, hop.port );
This example shows how to use WRP (Web Reactive Programming) to automatically update client interfaces upon server updates.
A reactor is created from the the server event clients
. Each time
the server broadcast this event, i.e., on each new connection,
all the already connected clients are updated to reflect the number
of connected clients and their connection times.
HTML tag
<REACT>
The body of a <react>
node is client script that gets re-evaluated
each time of its source is modified. The result of that evaluated in
inserted in the DOM tree, possibly replacing already created dynamic
nodes.
react/react.js
service react() {
return <html>
~{
var width = hop.reactProxy( { val: 2 } );
var els = hop.reactProxy( [ "foo", "bar", "gee" ] );
}
<button onclick=~{width.val++ }>
enlarge
</button>
<button onclick=~{els.push( "#" + els.length ) }>
push
</button>
<table style=~{`border: ${width.val}px solid red`}>
<react>
~{els.map( function( el ) { return <tr><td>1: ${el}</td></tr> } )}
</react>
</table>
<table style=~{`border: ${width.val * 2}px solid green`}>
<react>
~{els.map( function( el ) { return <tr><td>2: ${el}</td></tr> } )}
</react>
</table>
</html>
}
console.log( "Go to \"http://%s:%d/hop/react\"", hop.hostname, hop.port );
This example illustrates Web Reactive Programming (WRP) in Hop.
It creates two reactors (width
and els
) and two reactive
HTML nodes (the two tables). When the width
reactor is modified
(via the enlarge
button) the table borders automatically enlarge. When
the els
reactor is modified (via the push
button), new elements
are added to the two tables.