I am new to react js.I have a problem in rendering the pretty json data inside textarea.I don't know Which part is wrong
I want my prettyjson to render inside textarea Like this
"email":"xxxx#x.com",
"email":"yyyy#y.com",
.....
This is my code
But I am getting Nothing inside my textarea
/**
* Created by arfo on 6/26/2016.
*/
var React =require('react');
var api = require('../utils');
var Bulkmail = React.createClass({
getInitialState:function () {
return{
default:10,
data:[],
color:'#58FA58'
}
},
componentDidMount:function () {
api.getemail(this.state.default).then(function (response) {
this.setState({
data:response
})
}.bind(this))
},
onSubmit:function (e) {
e.preventDefault();
console.log(this.refs.text.value.trim());
},
onChange:function (e) {
e.preventDefault();
//console.log(this.refs.text.value.trim())
var data = this.refs.text.value.trim();
if(isNaN(data)){
this.setState({
color:'#FE2E2E'
})
}else{
this.setState({
color:'#58FA58'
})
}
},
render:function () {
console.log(this.state.data);
var results = this.state.data;
return(
<div className="bodybox">
<div className="box">
<div className="upc">
<p>Generate Bulk Email</p>
<form onSubmit={this.onSubmit}>
<input onChange={this.onChange} type="text" style={{border:'1px solid '+this.state.color}} ref="text" defaultValue={this.state.default} placeholder="Enter Number"/>
<button>Get Data</button>
</form>
<div className="result">
<ul>
{this.state.data.map(function (data) {
return <li key={data.id}>{data.email}</li>
})}
</ul>
</div>
</div>
<div className="tdown">
<p>Json Format</p>
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
<textarea defaultValue={this.state.data.map(function(data) {
return JSON.stringify(data.email)
})} >
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
</textarea>
</div>
</div>
</div>
)
}
});
module.exports = Bulkmail ;
No need to use difficult regex, we can use functionality from JSON.stringify(object, undefined, 2) to get beautifully rendered strings from JSON.
var obj={"glossary":{"title":"example glossary","GlossDiv":{"title":"S","GlossList":{"GlossEntry":{"ID":"SGML","SortAs":"SGML","GlossTerm":"Standard Generalized Markup Language","Acronym":"SGML","Abbrev":"ISO 8879:1986","GlossDef":{"para":"A meta-markup language, used to create markup languages such as DocBook.","GlossSeeAlso":["GML","XML"]},"GlossSee":"markup"}}}}}
var pretty = JSON.stringify(obj, undefined, 2);
var ugly = document.getElementById('myTextArea').value; document.getElementById('myTextArea').value = pretty;
<textarea value={this.state.data.map(e=>JSON.stringify(e))} defaultValue="val" />
result {"email":"some#mail"},{"email":"some#mail"},{"email":"some#mail"}
let value = this.state.data.map(e=>JSON.stringify(e).replace(/{|}/g,''));
<textarea value={value} defaultValue="val" />
result "email" : "xx#yy.y", "email" : "some#mail", "email" : "some#mail"
let value = this.state.data.map(e=>JSON.stringify(e).replace(/{|}/g,'')).join(',\n');
<textarea value={value} defaultValue="val" />
result "email" : "xx#yy.y",
"email" : "some#mail",
"email" : "some#mail"
In HTML, the value of is set via children. In React, you should use value instead.
/**
* Created by arfo on 6/26/2016.
*/
var React =require('react');
var api = require('../utils');
var Bulkmail = React.createClass({
getInitialState:function () {
return{
default:10,
data:[],
color:'#58FA58'
}
},
componentDidMount:function () {
api.getemail(this.state.default).then(function (response) {
this.setState({
data:response
})
}.bind(this))
},
onSubmit:function (e) {
e.preventDefault();
console.log(this.refs.text.value.trim());
},
onChange:function (e) {
e.preventDefault();
//console.log(this.refs.text.value.trim())
var data = this.refs.text.value.trim();
if(isNaN(data)){
this.setState({
color:'#FE2E2E'
})
}else{
this.setState({
color:'#58FA58'
})
}
},
getEmailValue:function(){
return this.state.data.map(function(data) {
return JSON.stringify(data.email)
}).join('\n');
},
render:function () {
console.log(this.state.data);
var results = this.state.data;
return(
<div className="bodybox">
<div className="box">
<div className="upc">
<p>Generate Bulk Email</p>
<form onSubmit={this.onSubmit}>
<input onChange={this.onChange} type="text" style={{border:'1px solid '+this.state.color}} ref="text" defaultValue={this.state.default} placeholder="Enter Number"/>
<button>Get Data</button>
</form>
<div className="result">
<ul>
{this.state.data.map(function (data) {
return <li key={data.id}>{data.email}</li>
})}
</ul>
</div>
</div>
<div className="tdown">
<p>Json Format</p>
<textarea value={getEmailValue()}
</textarea>
</div>
</div>
</div>
)
}
});
Related
i just enter to "REACT " world to do my front-end off my own project and i have problem for 2 day with the function map , i get data from my back-end and i just save the id in the Cuartos array , i dont know what its my error , i try it with for loop with console.log in a function out of render and it work , but work out of the render function how i can resolve it ? i need to get all the cuarto id in the render
this is my code
class FormInterruptor extends React.Component {
constructor (){
super();
const axx={au:[]};
const Cuartos = [];
axios.get("http://localhost:5000/API/Cuartos")
.then(response => {
const a=JSON.stringify(response.data);
console.log(response.data);
axx.au=response.data;
const b=JSON.stringify(axx.au.idcuarto);
console.log("aqui estas" )
for (let i = 1; i < b.length; i=i+2)
{
Cuartos.push({idcuarto:parseInt((JSON.stringify(axx.au.idcuarto))[i])});
}
});
this.state = {
IdInterruptor: '',
IdCuarto: '',
Pin: '',
Dimmer: '',
Cuartos
};
}
onChange(e){
this.setState({
[e.target.name]:e.target.value
});
}
handleSubmit = event => {
event.preventDefault();
const Luz = {
IdInterruptor: this.state.IdInterruptor,
IdCuarto: this.state.IdCuarto,
Pin: this.state.Pin,
Dimmer: this.state.Dimmer
};
//AYUDA CON EL LUGAR DODNE SE PONDRA EL INTERRUPTOR
let config = {headers: {'Access-Control-Allow-Origin': "*"}};
axios.post('http://localhost:5000/API/Cuarto/1/Luz/add', Luz , config)
.then(res => {
//console.log(res);
console.log(res.data);
})
}
render(){
return (
<div className="App">
<header className="App-header">
<img src={process.env.PUBLIC_URL + '/Images/Escudo.png'} alt='Escudo' width='400'/>
<div className="Formulario">
<h2>
Formulario Luz
</h2>
<form onSubmit={this.handleSubmit} >
<div id='form'>
<input id="form" type="text"placeholder="ID del interruptor" value={this.state.IdInterruptor} name="IdInterruptor" onChange={this.onChange.bind(this)} />
</div>
<div id="separador">
<select id="form" name="IdCuarto" value={this.state.IdCuarto} onChange={this.onChange.bind(this)} >
</select>
</div>
<div id="separador">
<input id="form" type="text" name="Pin" placeholder="Pin" value={this.state.Pin} onChange={this.onChange.bind(this)} />
</div>
<div id="separador">
<input id="form" type="text" name="Dimmer" placeholder ="Dimmer" value={this.state.Dimmer} onChange={this.onChange.bind(this)}/>
</div>
<div >
<input type="submit" value="Submit" className="button" onChange={this.onChange}/>
</div>
</form>
</div>
<div>
{this.state.Cuartos.map(p => {
return <p > {p.idcuarto} !</p>}
)}
</div>
</header>
</div>
);
}
}
export default FormInterruptor
Update:
i change the code and i change my state in the componentDidMount and
this is my data array of Cuartos how i need to use the map function
enter image description here
First and foremost, what you should be doing is to make the HTTP request in the ComponentDidMount lifecycle hook instead of the constructor, as the purpose of the constructor is only for
Initializing local state by assigning an object to this.state. Binding
event handler methods to an instance.
constructor(props) {
super(props);
this.state = {
IdInterruptor: '',
IdCuarto: '',
Pin: '',
Dimmer: '',
Cuartos: undefined,
}
}
componentDidMount() {
let Cuartos;
axios.get("http://localhost:5000/API/Cuartos")
.then(response => {
const a=JSON.stringify(response.data);
console.log(response.data);
axx.au=response.data;
const b=JSON.stringify(axx.au.idcuarto);
console.log("aqui estas" )
for (let i = 1; i < b.length; i=i+2) {
Cuartos.push({idcuarto:parseInt((JSON.stringify(axx.au.idcuarto))[i])});
}
this.setState({ Cuartos });
});
}
Then, on your render, you should carry out a check such that you will only carry out Array.map() when the request is returned, and that Cuartos is defined, and the idcuartos array is not empty.
render() {
const { Cuartos } = this.state;
return <>
<div>
{
Cuartos && Cuartos.idcuartos.length && Cuartos.idcuartos.map(p => {
return . <p>{q}</p>
})
}
</div>
</>
}
Make your api call in componentDidMount and save your data to state and then manipulate your data before rendering.
class FormInterruptor extends React.Component {
constructor (){
super();
this.state = {
IdInterruptor: '',
IdCuarto: '',
Pin: '',
Dimmer: '',
Cuartos:[]
};
}
componentDidMount(){
axios.get("http://localhost:5000/API/Cuartos")
.then(response => this.setState({Cuartos:res.data}));
}
onChange(e){
this.setState({
[e.target.name]:e.target.value
});
}
handleSubmit = event => {
event.preventDefault();
const Luz = {
IdInterruptor: this.state.IdInterruptor,
IdCuarto: this.state.IdCuarto,
Pin: this.state.Pin,
Dimmer: this.state.Dimmer
};
//AYUDA CON EL LUGAR DODNE SE PONDRA EL INTERRUPTOR
let config = {headers: {'Access-Control-Allow-Origin': "*"}};
axios.post('http://localhost:5000/API/Cuarto/1/Luz/add', Luz , config)
.then(res => {
//console.log(res);
console.log(res.data);
})
}
render(){
return (
<div className="App">
<header className="App-header">
<img src={process.env.PUBLIC_URL + '/Images/Escudo.png'} alt='Escudo' width='400'/>
<div className="Formulario">
<h2>
Formulario Luz
</h2>
<form onSubmit={this.handleSubmit} >
<div id='form'>
<input id="form" type="text"placeholder="ID del interruptor" value={this.state.IdInterruptor} name="IdInterruptor" onChange={this.onChange.bind(this)} />
</div>
<div id="separador">
<select id="form" name="IdCuarto" value={this.state.IdCuarto} onChange={this.onChange.bind(this)} >
</select>
</div>
<div id="separador">
<input id="form" type="text" name="Pin" placeholder="Pin" value={this.state.Pin} onChange={this.onChange.bind(this)} />
</div>
<div id="separador">
<input id="form" type="text" name="Dimmer" placeholder ="Dimmer" value={this.state.Dimmer} onChange={this.onChange.bind(this)}/>
</div>
<div >
<input type="submit" value="Submit" className="button" onChange={this.onChange}/>
</div>
</form>
</div>
<div>
{this.state.Cuartos.map(p => {
return <p > {p.idcuarto} !</p>}
)}
</div>
</header>
</div>
);
}
}
export default FormInterruptor
You are making a call in the constructor which is not recommended, try doing it in componentDidMount
Javascript is asynchronous so when are making a call using axios it will not wait until the response got back it will continue to render the component, you need to update your component after you got the response
If you still want to render with your existing code, add below line after the for loop inside the axios call back
this.setState({"Cuartos": Cuartos})
I am creating one react form which looks like wizard type means on click of next button, it will load another component.
To do with this, i am using javascript iterators. I am updating state based on what iterator returns but i dont understand its not updating state of the component.
Code:
console.clear();
var Email = React.createClass({
render: function() {
return (
<div className="form-group">
<label className="control-label">Email:</label>
<input className="form-control" />
</div>
);
}
});
var Password = React.createClass({
render: function() {
return (
<div className="form-group">
<label className="control-label">Password:</label>
<input className="form-control" />
</div>
);
}
});
var Contact = React.createClass({
render: function() {
return (
<div className="form-group">
<label className="control-label">Contact:</label>
<input className="form-control" />
</div>
);
}
});
var Form = React.createClass({
getInitialState: function(){
this.fit = this.flowIterator([<Email />,<Password />,<Contact />]);
return {
view: this.fit.next(),
submitBtnText: "Next"
};
},
flowIterator: function(array){
var nextIndex = 0;
return {
next: function(){
console.log("nextIndex=",nextIndex);
console.log("array.length-1=",array.length-1);
console.log("nextIndex == array.length-1 =",nextIndex == array.length-1);
return nextIndex == array.length-1 ?
{value: array[nextIndex++], done: true} :
{value: array[nextIndex++], done: false};
}
}
},
onFormSubmit: function(e){
this.setState({
onChange: this.onStateChange()
});
e.preventDefault();
},
onStateChange: function(){
console.log("State change event fired!!");
this.setState({
view: this.fit.next(),
submitBtnText: "Next"
});
console.log("this.state.view.done=",this.state.view.done);
if(this.state.view.done){
this.setState({
submitBtnText: "Login"
});
}
},
render: function() {
return (
<form className="form-horizontal col-xs-6" onSubmit={this.onFormSubmit}>
{this.state.view.value}
<div className="form-group">
<button className="btn btn-success pull-right">{this.state.submitBtnText}</button>
</div>
</form>
);
}
});
ReactDOM.render(
<Form />,
document.getElementById('container')
);
check the code in jsfiddle
Thank you...
// initial state and other properties
var ReviewControl = React.createClass({
getInitialState: function() {
return {
name:'',
feedback:'',
movie:'',
reviews:[]
};
},
onChangeName:function(el){
this.setState({name:el.target.value})
},
onChangeFeedback:function(el) {
this.setState({feedback:el.target.value})
},
onChangeMovie:function(el){
this.setState({agent:el.target.value})
},
submitReview:function(el) {
//preventing default for the form
el.preventDefault();
//storing data into the reviews array created earlier
this.state.reviews.push(
{name:this.state.name, feedback:this.state.feedback, movie:this.state.movie});
this.setState({name:'', feedback:''});
},
render: function() {
var options = this.props.list.map(function(agent){
return (<option key={agent.id} value={agent.agentName}>{agent.agentName}</option>);
});
//rendering the form for feedback
return (
<div>
//creating form
<form onSubmit = {this.submitReview}>
<lable> Agent Name : </lable>
<input type="text" placeholder='Enter The Agent Name' value={this.state.name} onChange={this.onChangeName} />
<br/><br/>
<lable> Feedback : </lable>
<input type="text" placeholder='Enter Your Feedback' value={this.state.feedback} onChange={this.onChangeFeedback} />
<br/><br/>
<select onChange={this.onChangeMovie}>
{options}
</select>
<br/><br/>
<input type="submit" value="Submit"/>
</form>
//collecting the reviews
<ReviewCollection reviews = {this.state.reviews} />
</div>
)
}
});
// collecting all the reviews from the user and storing it
var ReviewCollection = React.createClass ({
render:function () {
var reviews = this.props.reviews.map(function(review) {
return <Review key={review.id} movie = {review.movie} name = {review.name} feedback = {review.feedback} />
});
return (<div> {reviews} </div>)
}
});
//showing the stored values from the array review
var Review = React.createClass({
render:function(){
return <div>
<span> Agent Name </span>
{this.props.name}
<br/>
<span> Movie Name </span>
{this.props.movie}
<br/>
<span> Feedback </span>
{this.props.feedback}
<br/>
</div>
}
});
// rendering the form
var finalReview = <ReviewControl list={agentList} />;
ReactDOM.render(finalReview, document.getElementById('myid'));
You aren't setting the new review state in submitReview. Just pushing into the old array isn't actually updating state. You have to explicitly update it.
this.state.reviews.push({
name: this.state.name,
feedback: this.state.feedback,
movie: this.state.movie
});
this.setState({
name: '',
feedback: '',
reviews: this.state.reviews
});
Another small thing I noticed is that you're using el as the argument for events. Typically it's just e or event. el is usually short for element, usually a dom node.
JSFiddle: https://jsfiddle.net/morahood/cp569zg6/38/
When I delete a child ServiceItem component from the ServiceList component, I am running into an issue where the last ServiceItem in the list is removed instead of the targeted ServiceItem. The JSFiddle link above will help understand the issue, just make sure you enter in some identifiable information in the input fields so you can see what is getting deleted.
How do I fix my application so that the respective component is deleted?
var ServiceForm = React.createClass({
render: function() {
return (
<form onSubmit={ this.handleFormSubmission } >
{ this.renderServiceItemList() }
<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: [this.renderServiceItem]
});
},
handleFormSubmission: function(event) {
event.preventDefault();
var data = this.refs.service_item_list.getAllServiceItems();
var json = {
"service_request" : {
"services" : data,
"additional_recipients" : 'test#example.com',
"comments" : 'Hello world!'
}
};
console.log(json);
},
addServiceItem: function(event) {
var copy = this.state.serviceItems.slice();
copy.push(this.renderServiceItem);
this.setState({
serviceItems: copy
});
},
renderServiceItem: function(item, i) {
return (
<ServiceItem removeServiceItem={ this.removeServiceItem } data={item} key={i} ref={"service_item_" + i} />
);
},
removeServiceItem: function(event) {
var index = parseInt(event.target.value, 10);
var copy = this.state.serviceItems.slice();
copy.splice(index, 1);
this.setState({
serviceItems: copy
});
},
renderServiceItemList: function() {
return (
<ServiceItemList serviceItems={ this.state.serviceItems }
renderServiceItem={ this.renderServiceItem }
removeServiceItem={ this.removeServiceItem }
ref="service_item_list" />
);
}
});
var ServiceItemList = React.createClass({
render: function() {
var content;
if (this.props.serviceItems.length < 1) {
content = <div className="empty-service-list">There are no service items, click on append new service item below!</div>;
} else {
content = this.props.serviceItems.map(this.props.renderServiceItem);
}
return (
<div>
{ content }
</div>
);
},
getAllServiceItems: function() {
var data = [];
for (var ref in this.refs) {
data.push(this.refs[ref].serializeItem());
}
var merged = [].concat.apply([], data);
return(merged);
}
});
var ServiceItem = React.createClass({
render: function() {
return (
<div className="row">
<div className="col-sm-3">
<div className="form-group service-item">
<label>Service Item </label>
<select multiple ref="service_types" 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 ref="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 ref="manufacturer" 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 ref="model" type="text" className="form-control" />
</div>
<a href="#" onClick={ this.props.removeServiceItem }>
<span aria-hidden="true" className="remove-fields" onClick={ this.props.removeServiceItem }>×</span>
</a>
</div>
</div>
</div>
);
},
getInitialState: function() {
return({
service_types: [],
customer: '',
manufacturer: '',
model: ''
});
},
serializeItem: function() {
var customer = this.refs.customer.value;
var manufacturer = this.refs.manufacturer.value;
var model = this.refs.model.value;
var selected = this.getSelectedServiceItems();
var services = this.getSelectedServiceItems().map(function(item) {
return (
{
"service" : {
"service_type" : item,
"customer" : customer,
"manufacturer" : manufacturer,
"model" : model
}
}
)
});
return(services);
},
getSelectedServiceItems: function() {
var select = this.refs.service_types;
var values = [].filter.call(select.options, function (o) {
return o.selected;
}).map(function (o) {
return o.value;
});
return(values);
}
});
ReactDOM.render(
<ServiceForm />,
document.getElementById('container')
);
Your issue is with your key={i}.
React lists requires the key of an item to be unique to the item, regardless of the position of the item in the list. This allows react to do smart management of the list in case of updates.
React will NOT render the following update correctly:
From: To:
name: key: name: key:
Bill 0 Bill 0
Charlie 1 Dave 1
Dave 2
Because react thinks that the Charlie record is unchanged (because the key is unchanged).
I would advise you to put some sort of ID from the service-item retrieved as key.
On name, e.g.
From: To:
name: key: name: key:
Bill Bill Bill Bill
Charlie Charlie Dave Dave
Dave Dave
React will render the update correctly in this case (because key is unique to the item).
I am still learning React and Javascript so thank you for your patience.
I am trying to serialize my form data so I can send it to a Ruby on Rails back end for processing. I am just using vanilla React with no additional depedencies like Flux, Redux, etc.
It seems like my child components are not returning anything and I am not quite sure why.
I have tried:
exposing values through the use of refs (but failed and read that it isn't really a good idea to do that anyway)
exposing a parent method within my child components to gather information about each individual component (what you will see in my jsfiddle).
updating component states through onChange methods and trying to access the states of each child component
My JSFiddle: https://jsfiddle.net/morahood/0ptdpfu7/91/
I am clearly missing a key element of React design patterns here. Am I just way off track? How can I get back on track? I would like to eventually be able to serialize the form data in the 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" be way overcomplicating things here. The DOM element for <form> can actually be treated as an array of all the inner <input> elements. In other words, if you have:
render: function() {
return (
<form ref="form">
...
</form>
);
}
All your input elements can be accessed by:
serialized = {}
for (var i in this.refs.form) {
var input = this.refs.form[i];
serialized[input.name] = input.value;
}
This might not provide you with enough flexibility. A better solution might be to define methods in your component instances that return the 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 you need multiple service items, you'll probably need to rely on this.props.children to access each component instance rather than 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 all your state logic into this 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() {
// You can still access your input elements through refs in here
...
},
render: function() {
...
}
});
Note that I'm using React.Children here rather than simply using this.props.children because when there's only a single child, children is not an array (see: https://facebook.github.io/react/tips/children-props-type.html).
You could use react.rb and reactive-record which will do all this for you out of the box. http://reactrb.org