javascript - How do I get my components to return a serialization of themselves? -


i still learning react , javascript thank patience.

i trying serialize form data can send ruby on rails end processing. using vanilla react no additional depedencies flux, redux, etc.

it seems child components not returning , not quite sure why.

i have tried:

  • exposing values through use of refs (but failed , read isn't idea anyway)
  • exposing parent method within child components gather information each individual component (what see in jsfiddle).
  • updating component states through onchange methods , trying access states of each child component

my jsfiddle: https://jsfiddle.net/morahood/0ptdpfu7/91/

i missing key element of react design patterns here. way off track? how can on track? able serialize form data in following format

{    "service_request" : {       "services" : [         {           "service_item" : ["oil change", "new windshield wipers"],           "customer" : "troy",           "manufacturer" : "ford",           "model" : "f150"         },         {           "service_item" : ["tire rotation"],           "customer" : "dave",           "manufacturer" : "hyundai",           "model" : "genesis"         }       ]     } } 

components

var serviceform = react.createclass({   render: function() {     return (       <form onsubmit={ this.handleformsubmission }>         { this.state.serviceitems.map(function(item) {           return (item);         })}         <div classname="btn btn-default btn-sm" onclick={ this.addserviceitem }>+ append new service item</div>         <button type="submit" classname="btn btn-success btn-lg pull-right">submit</button>       </form>     );   },    getinitialstate: function() {     return ({       serviceitems: [<serviceitem serializeserviceitem={ this.serializeserviceitem } />]     });   },    handleformsubmission: function() {     console.log("form submitted!");     alert("serialized form data: " +  this.serializeformdata());   },    addserviceitem: function(event) {     var serviceitems = this.state.serviceitems;     serviceitems.push(<serviceitem serializeserviceitem={ this.serializeserviceitem } />);      this.setstate({       serviceitems: serviceitems     });   },    serializeserviceitem: function() {     var jsondata = {       "service_item" : this.state.service_items,       "customer" : this.state.customer,       "manufacturer" : this.state.manufacturer,       "model" : this.state.model     }     return (jsondata);       },    serializeformdata: function() {     return( this.state.serviceitems.map(function(item) {       return (item.serializeserviceitem);     }));   } });  var serviceitem = react.createclass({   render: function() {     return (       <div classname="row">         <div classname="col-sm-3">           <div classname="form-group">             <label>service item </label>             <select multiple name="service_item" selected={ this.state.service_items } classname="form-control">               <option>oil change</option>               <option>tire rotation</option>               <option>new wiper blades</option>             </select>           </div>         </div>          <div classname="col-sm-3">           <div classname="form-group">             <label>customer </label>             <select name="customer" selected={ this.state.customer } classname="form-control">               <option>troy</option>               <option>dave</option>               <option>brandon</option>             </select>           </div>         </div>                  <div classname="col-sm-3">           <div classname="form-group">             <label>manufacturer </label>             <div classname="input-group">                <input name="manufacturer" value={ this.state.manufacturer } onchange={ this.setmanufacturer } type="text" classname="form-control" />             </div>           </div>         </div>           <div classname="col-sm-3">           <div classname="form-group">             <label>model </label>             <div classname="input-group">                <input name="model" value={ this.state.model } onchange={ this.setmodel } type="text" classname="form-control" />             </div>           </div>         </div>       </div>     );   },    getinitialstate: function() {     return({       service_items: [],       customer: "",       manufacturer: "",       model: ""     });   },    setmodel: function(event) {     this.setstate({ model: event.target.value });   },    setmanufacturer: function(event) {      this.setstate({ manufacturer: event.target.value });   },    setcustomer: function(event) {     this.setstate({ customer: event.target.selected });   },    setserviceitems: function(event) {     this.setstate({ service_items: event.target.selected });   } });  reactdom.render(   <serviceform />,   document.getelementbyid('container') ); 

solution

https://jsfiddle.net/morahood/cp569zg6/19/

you "might" way overcomplicating things here. dom element <form> can treated array of inner <input> elements. in other words, if have:

render: function() {   return (     <form ref="form">       ...     </form>   ); } 

all input elements can accessed by:

serialized = {} (var in this.refs.form) {   var input = this.refs.form[i];   serialized[input.name] = input.value; } 

this might not provide enough flexibility. better solution might define methods in component instances return input values:

var serviceform = react.createclass({   serializeformdata: function() {     return {       foo: this.refs.foo.serialize()     };   },    render: function() {      var foo = this.state.foo;      return (        <serviceitem data={foo} ref="foo" />      );   } });  var serviceitem = react.createclass({   serialize: function() {     return {       model: this.refs.model.value,       ...     }   },    render: function() {     var model = this.props.data.model;     return (       <input ref="model" value={model} ... />     );   } }); 

if need multiple service items, you'll need rely on this.props.children access each component instance rather on this.refs:

var servicecontainer = react.createclass({   collectformdata: function() {     return this.refs.form.serialize();   },    renderserviceitem: function(item, i) {     return (       <serviceitem data={item} key={i} />     );   },    render: function() {     // assuming you've moved state logic servicecontainer     var serviceitems = this.state.serviceitems;     return (       <serviceform ref="form">         {serviceitems.map(this.renderserviceitem)}       </serviceform>     );   } });  var serviceform = react.createclass({   serialize: function() {     return react.children.map(this.props.children, function(item) {       return item.serialize();     });   },    render: function() {     return (       <div>{this.props.children}</div>     );   } });  var serviceitem = react.createclass({   serialize: function() {     // can still access input elements through refs in here     ...   },    render: function() {     ...   } }); 

note i'm using react.children here rather using this.props.children because when there's single child, children not array (see: https://facebook.github.io/react/tips/children-props-type.html).


Comments

Popular posts from this blog

sublimetext3 - what keyboard shortcut is to comment/uncomment for this script tag in sublime -

java - No use of nillable="0" in SOAP Webservice -

ubuntu - Laravel 5.2 quickstart guide gives Not Found Error -