react-binding v0.9.1
react-binding
React-binding is lightweight utility for two-way data binding in React.
import React from 'react';
import ReactDOM from 'react-dom';
import Binder from 'react-binding';
export default class Form extends React.Component {
constructor(props){
super(props);
this.state = {data: {}};
},
render {
return (
<div>
<input valueLink={Binder.bindToState(this,"data", "Employee.FirstName")} />
<div>FirstName: {this.state.data.Employee.FirstName}</div>
</div>
)}
});
ReactDOM.render(
<Form />,
document.getElementById('content')
);
Features:
- No dependencies.
- Minimal interface - using path with dot notation.
- Support for complex objects.
- Support for collection-based structures - arrays and lists.
- Support for value converters.
- No need to define initial values, nested structures. Binder creates this for you.
- Support concept for references to allow JSON to be used to represent graph information.
react-binding offers two-way data binding support for:
- object properties with path expression (dot notation)
- Binder.bindToState(this,"data","Employee.FirstName");
- Binder.bindToState(this,"data","Employee.Contact.Email");
- complex objects (json) with nested properties
- Binder.bindTo(employee,"FirstName");
- Binder.bindTo(employee,"Contact.Email");
- collection-based structures - arrays and lists
- model={Binder.bindArrayToState(this,"data","Hobbies")}
- this.props.model.items.map(function(item){ return ();})
- this.props.model.add()
- this.props.model.remove(item)
- model={Binder.bindArrayToState(this,"data","Hobbies")}
- supports for "value/requestChange" interface also to enable to use ReactLink attribute
- valueLink={Binder.bindTo(employee,"FirstName")}
- enables binding with value converters
- supports both directions - format (toView) and parse (fromView)
- support for converter parameter - valueLink={Binder.bindToState(this,"data", "Duration.From",converter, "DD.MM.YYYY")}
- converter parameter can be data-bound - valueLink={Binder.bindToState(this,"data", "Duration.From",converter, this.state.format)}
- usable with any css frameworks
Basic principle
Each bindTo return and uses interface called "value/onChange". Each bindTo component is passed a value (to render it to UI) as well as setter to a value that triggers a re-render (typically at the top location).
The re-render is done in the component where you bind to the state via (bindToState, bindArrayToState).
BindTo can be nested - composed to support components composition. Then path is concatenate according to parent-child relationship.
Get started
npm install react-binding
bower install react-binding
npm install -g browserify
npm install reactify
browserify ./index.js > bundle.js
minimal example
import React from 'react';
import ReactDOM from 'react-dom';
import Binder from 'react-binding';
export default class Form extends React.Component {
constructor(props){
super(props);
this.state = {data: {}};
},
render {
return (
<div>
<input valueLink={Binder.bindToState(this,"data", "Employee.FirstName")} />
<div>FirstName: {this.state.data.Employee.FirstName}</div>
</div>
)}
});
ReactDOM.render(
<Form />,
document.getElementById('content')
);
Note: React-binding as mixins - use npm install react-binding@0.6.4
Overview
bindToState(key,pathExpression)
It enables to bind to object property with path expression
- using ReactLink
<input type='text' valueLink={Binder.bindToState(this,"data","Employee.Contact.Email")} />
- without ReactLink
<TextBoxInput model={Binder.bindToState(this,"data","Employee.Contact.Email")} />
var TextBoxInput = React.createClass({
render: function() {
var valueModel = this.props.model;
var handleChange = function(e){
valueModel.value = e.target.value;
}
return (
<input type='text' onChange={handleChange} value={valueModel.value} />
)
}
});
bindTo(parent,pathExpression)
It enables to bind to complex object with nested properties and reuse bindings in components.
- binding to state at root level
<PersonComponent personModel={Binder.bindToState(this,"data","Employee")} />
<PersonComponent personModel={Binder.bindToState(this,"data","Deputy")} />
- binding to parent
<input type='text' valueLink={Binder.bindTo(this.props.personModel,"Contact.Email")} />
- reuse bindings in component
var PersonComponent = React.createClass({
render: function() {
return (
<div>
<input type='text' valueLink={Binder.bindTo(this.props.personModel,"FirstName")} />
<input type='text' valueLink={Binder.bindTo(this.props.personModel,"LastName")} />
<input type='text' valueLink={Binder.bindTo(this.props.personModel,"Contact.Email")} />
</div>
);
}
});
bindArrayToState(key,pathExpression)
It enables binding to collection-based structures (array). It enables to add and remove items.
- binding to array
<HobbyList model={Binder.bindArrayToState(this,"data","Hobbies")} />
- access items (this.props.model.items)
var HobbyList = React.createClass({
render: function() {
if (this.props.model.items === undefined) return <span>There are no items.</span>;
var hobbies = this.props.model.items.map(function(hobby, index) {
return (
<Hobby model={hobby} key={index} onDelete={this.handleDelete} />
);
},this);
return (
<div>{hobbies}</div>
);
}
});
- add new items (this.props.model.add(newItem?))
handleAdd: function(){
return this.props.model.add();
},
- remove exiting items (this.props.model.props.delete(item))
handleDelete: function(hobby){
return this.props.model.remove(hobby);
},
bindArrayTo(parent,pathExpression)
It enables binding to collection-based structures (array) for nested arrays. It enables to add and remove items.
- binding to array
<HobbyList model={Binder.bindArrayTo(this,parent,"Hobbies")} />
- access items (this.props.model.items)
var HobbyList = React.createClass({
render: function() {
if (this.props.model.items === undefined) return <span>There are no items.</span>;
var hobbies = this.props.model.items.map(function(hobby, index) {
return (
<Hobby model={hobby} key={index} onDelete={this.handleDelete} />
);
},this);
return (
<div>{hobbies}</div>
);
}
});
- add new items (this.props.model.add(newItem?))
handleAdd: function(){
return this.props.model.add();
},
- remove exiting items (this.props.model.props.delete(item))
handleDelete: function(hobby){
return this.props.model.remove(hobby);
},
Value converters
Value converters
- format - translates data to a format suitable for the view
- parse - convert data from the view to a format expected by your data (typically when using two-way binding with input elements to data).
Example - date converter -> using parameters 'dateFormat' is optional
var dateConverter = function() {
this.parse = function (input, dateFormat) {
if (!!!input) return undefined;
if (input.length < 8) return undefined;
var date = moment(input, dateFormat);
if (date.isValid()) return date.toDate();
return undefined;
}
this.format = function (input,dateFormat) {
if (!!!input) return undefined;
return moment(input).format(dateFormat);
}
}
using converter
<DatePicker label="From" model={Binder.bindToState(this,"data", "Duration.From", converter, 'DD.MM.YYYY')} error={this.validationResult().Duration.From} />
<DatePicker label="To" model={Binder.bindToState(this,"data", "Duration.To", converter, 'DD.MM.YYYY')} error={this.validationResult().Duration.To} />
References
JSON models trees, and most application domains are graphs. Binding supports concept for references to allow JSON to be used to represent graph information.
- Each entity is inserted into a single, globally unique location in the JSON with a unique identifier.
- Each reference is an object of the $type='ref' and must contain value as path to single, globally unique location in the JSON - {$type:'ref',value:'todosById',44}
{
todosById: {
"44": {
name: "get milk from corner store",
done: false,
prerequisites: [{ $type: "ref", value: ["todosById", 54] }]
},
"54": {
name: "withdraw money from ATM",
done: false,
prerequisites: []
}
},
todos: [
{ $type: "ref", value: ["todosById", 44] },
{ $type: "ref", value: ["todosById", 54] }
]
};
Examples
hobby form - data binding only
- no UI framework - try in Plunker
- with react-bootstrap - try in Plunker
hobby form with validation using business-rules-engine
- no UI framework - try in Plunker
- with react-bootstrap - try in Plunker
- with material-ui
value converters
- date picker - try in Plunker
Contact
For more information on react-binding please check out my blog.
8 years ago
8 years ago
9 years ago
9 years ago
9 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago