How do I delete specific child React components? - javascript

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

Related

React component state change issue

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...

How can I get my add function to only change contents of the selected index when editing state is true?

When the editing state is true, I want it so that when the user hits submit it changes for the item they chose to edit. Normally, it would add a new object if the user if not in editing mode. However, for some reason even though I call splice for the specific index, it only changes the first index. I have also tried to bind the button to i but still no luck.
const {
Modal,
Input,
Button
} = ReactBootstrap;
var modalName = "Add New Recipe";
var editRecipe = "";
var editIngredient = [];
var Recipes = React.createClass({
// hook up data model
getInitialState: function() {
return {
showModal: false,
editing: false,
recipeList: [
{recipe: "Malek's Protein Shake", ingredients: ['1 Glass of Whole Milk', '6 tablespoons of Peanut Butter', '1 scoop of Whey', '2 Bananas', '1 scoop of Vanilla Ice Cream']},
{recipe: 'Pumpkin Pie', ingredients: ['Pumpkin Puree', 'Sweetened Condensed Milk', 'Eggs', 'Pumpkin Pie Spice', 'Pie Crust']},
{recipe: 'Spaghetti with fried eggs', ingredients: ['Noodles', 'Tomato Sauce', 'Meatballs', '4 eggs', 'Ground black pepper']}
]
}
},
ingredientList: function(ingredients) {
return ingredients.map((ingredient, i) => {
return (<li key={i} index={i} className="list-group-item">{ingredient}</li>)
})
},
eachRecipe: function(item, i) {
return (
<div key={i} index={i} className="panel panel-default">
<div className="panel-heading"><h3 className="panel-title">{item.recipe}</h3></div>
<div className="panel-body">
<ul className="list-group">
{this.ingredientList(item.ingredients)}
</ul>
<button name={i} onClick={this.edit.bind(this, i)} type="button" className="btn-sm btn-info" data-toggle="modal" data-target="#myModal">Edit</button>
<button onClick={this.remove.bind(this, i)} type="button" className="btn-sm btn-danger">Remove</button>
</div>
</div>
)
},
add: function(i) {
var name = this.refs.userVal.value;
var items = this.refs.newIngredients.value.split(",");
if (this.state.editing) {
var cloneEdit = this.state.recipeList.slice();
cloneEdit.splice(i, 1, { recipe: name, ingredients: items });
this.setState({recipeList: cloneEdit});
}
else {
this.setState({recipeList: [...this.state.recipeList, { recipe: name, ingredients: items }]})
}
this.close();
},
edit: function(i, recipe, ingredients) {
this.setState({editing: true})
this.open();
modalName = "Edit";
var arr = this.state.recipeList.slice();
editRecipe = arr[i].recipe;
editIngredient = arr[i].ingredients;
},
remove: function(i) {
var arr = this.state.recipeList.slice(); //copy array
arr.splice(i, 1); //remove element
this.setState({recipeList: arr}); //update state
},
close() {
this.setState({editing: false});
this.setState({ showModal: false });
modalName = "Add New Recipe";
editRecipe = "";
editIngredient = "";
},
open() {
this.setState({ showModal: true });
},
render: function() {
return (
<div>
<div>
<button onClick={this.open} type="button" className="btn btn-success btn-lg" data-toggle="modal" data-target="#myModal">Add Recipe</button>
<Modal show={this.state.showModal} onHide={this.close}>
<Modal.Header closeButton>
<Modal.Title>{modalName}</Modal.Title>
</Modal.Header>
<Modal.Body>
<form>
<div className="form-group">
<label for="name">Recipe</label>
<input type="text" ref="userVal" className="form-control" id="name" placeholder="Recipe Name" defaultValue={editRecipe} required />
</div>
<div className="form-group">
<label for="ingredients">Ingredients</label>
<input type="text" ref="newIngredients" className="form-control" id="ingredients" placeholder="Enter Ingredients,Separated,By,Commas" defaultValue={editIngredient} required />
</div>
</form>
</Modal.Body>
<Modal.Footer>
<Button className="btn btn-primary" data-dismiss="modal" onClick={this.add}>Submit</Button>
<Button className="btn btn-default" onClick={this.close}>Close</Button>
</Modal.Footer>
</Modal>
<div className="panelArea">
{
this.state.recipeList.map(this.eachRecipe)
}
</div>
</div>
</div>
);
}
});
ReactDOM.render(
<Recipes />,
document.getElementById('master')
)
You are not capturing the index of the item being edited, so this.add is going to get the click event assigned to i. Therefore, splice isn't going to work as expected.
I suggest keeping something like an editIdx in state:
class YourComponet extends React.Component {
// ...
edit(i, recipe, ingredients) {
this.setState({
editing: true,
editIdx: i
});
// ...
this.open();
}
add() {
// ...
if (this.state.editing) {
var i = this.state.editIdx;
var cloneEdit = this.state.recipeList.slice();
cloneEdit.splice(i, 1, { recipe: name, ingredients: items });
this.setState({recipeList: cloneEdit});
} else {
this.setState({recipeList: [...this.state.recipeList, { recipe: name, ingredients: items }]})
}
this.close();
}
}

How to render Pretty json data inside text area React js?

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>
)
}
});

Reactjs props not showing up. How can I improve my code?

// 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.

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

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

Categories

Resources