0.9.1 • Published 8 years ago

react-binding v0.9.1

Weekly downloads
106
License
MIT
Repository
github
Last release
8 years ago

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)
  • 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

<input type='text' valueLink={Binder.bindToState(this,"data","Employee.Contact.Email")} />
<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} />

try in Plunker

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

hobby form with validation using business-rules-engine

value converters

Contact

For more information on react-binding please check out my blog.

0.9.1

8 years ago

0.9.0

8 years ago

0.8.2

8 years ago

0.8.1

8 years ago

0.8.0

8 years ago

0.7.5

9 years ago

0.7.4

9 years ago

0.7.3

9 years ago

0.7.2

9 years ago

0.7.1

9 years ago

0.6.4

10 years ago

0.6.3

10 years ago

0.6.2

10 years ago

0.6.0

10 years ago

0.5.0

10 years ago

0.4.0

10 years ago

0.3.0

10 years ago

0.1.0

10 years ago