0.9.1 • Published 7 years ago

react-binding v0.9.1

Weekly downloads
106
License
MIT
Repository
github
Last release
7 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

7 years ago

0.9.0

7 years ago

0.8.2

7 years ago

0.8.1

7 years ago

0.8.0

7 years ago

0.7.5

8 years ago

0.7.4

8 years ago

0.7.3

8 years ago

0.7.2

8 years ago

0.7.1

8 years ago

0.6.4

9 years ago

0.6.3

9 years ago

0.6.2

9 years ago

0.6.0

9 years ago

0.5.0

9 years ago

0.4.0

9 years ago

0.3.0

9 years ago

0.1.0

9 years ago