I cannot figure out why my handleDelete function isn't running. When I click 'Delete' nothing at all happens.
In dev tools I see the value for the delete button is correct but onClick with it's attributes doesn't show up at all.
var MainContainer = React.createClass({
getInitialState: function(){
return {
name: 'JK_MNO',
friends: [], //friends is items
text: ''
}
},
handleChange: function(e){
//like the onChange function
this.setState({
text: e.target.value
});
},
handleSubmit: function(e){
e.preventDefault();
if(this.state.text !== '') {
var nextfriend = this.state.friends.concat([{
text: this.state.text, id: Date.now()
}]);
var nextText = '';
this.setState({
friends: nextfriend, text: nextText
});
}
},
handleDelete: function(e){
console.log(this.state.friends);
this.friends.splice (this.props.friend.id);
this.setState({
friends: friends
});
},
render: function(){
return (
<div>
<h3> Name: {this.state.name} </h3>
<ShowList friends={this.state.friends} />
<form onSubmit={this.handleSubmit} >
Enter Friends: <input className="friendInput" onChange={this.handleChange} value={this.state.text} />
</form>
</div>
);
}
});
var ShowList = React.createClass({
render: function() {
var createFriend = function(friend) {
return (
<li key={friend.id}>{friend.text} <button onClick={this.props.handleDelete} value={friend.id}>Delete</button> </li>
);
};
return <ul>{this.props.friends.map(createFriend.bind(this))}</ul>;
}
});
ReactDOM.render(<MainContainer />, document.getElementById('container'));
https://jsfiddle.net/USERALPHA32/bdc9trux/
Very close! You just need to pass your delete function down to ShowList as a prop:
Current:
<ShowList friends={this.state.friends} />
Suggested:
<ShowList friends={this.state.friends} handleDelete={this.handleDelete} />
Related
I am trying to map out an object into inputs that can be updated onChange. everything works except the component never updates after this.setState().
var ItemModal = React.createClass({
getInitialState: function(){
return {
title: "",
cooktime: "",
ingredients: [],
instructions: ""
}
},
componentWillReceiveProps: function(nextProps) {
this.setState({
title: nextProps.inputVal.title,
cooktime: nextProps.inputVal.cooktime,
ingredients: nextProps.inputVal.ingredients,
instructions: nextProps.inputVal.instructions
});
},
handleChange: function(event){
var change = {};
console.log(event.target.id + " " + event.target.value)
change[event.target.id] = event.target.value;
console.log(change);
this.setState(change);
},
render: function (){
var handleChange = this.handleChange;
var inputVal = this.props.inputVal;
return (
<div id="itemModal">
<div id="modalContent">
{
Object.keys(this.props.inputVal).map(function(curr){
return <input id={curr} placeholder= "Recipe Name Here!" type="text" value= {inputVal[curr]|| ""} onChange = {handleChange.bind(this)}/>
})
}
</div>
</div>
);
}
});
link to code
goto ItemModal code I am mentioning is in there.
The handleChange is inside a class. So, you need to use this to access it within the class. Change your render as follows.
render: function (){
var handleChange = this.handleChange;
var inputVal = this.props.inputVal;
var _this = this;
return (
<div id="itemModal">
<div id="modalContent">
{
Object.keys(this.props.inputVal).map(function(curr){
return <input id={curr} placeholder= "Recipe Name Here!" type="text" value= {inputVal[curr]|| ""} onChange = {_this.handleChange.bind(_this)}/>
})
}
</div>
</div>
);
}
I have 2 component, how do I pass user entered value through onChange to parent component? I'm able to pass the 'trigger' upon onChange, but how to pass the value along?
https://jsfiddle.net/gboaxm30
var InputComp = React.createClass({
render: function() {
return (
<div>
<input type="text" onChange={this.props.newVal} />
</div>
);
}
});
var App = React.createClass({
getInitialState(){
return {
inputVal: 0
}
},
inputChangedHandler(props) {
//set user changed value to inputVal
console.log(props)
},
render() {
return(
<div>
<InputComp newVal={this.inputChangedHandler}/>
<h4>{this.state.inputVal}</h4>
</div>
)
}
})
ReactDOM.render(
<App />,
document.getElementById('container')
);
Call a function on the onChange event of the child component and then access the value of input like e.target.value and then pass it to the parent component like this.props.newVal(e.target.value);
var InputComp = React.createClass({
handleChange(e) {
this.props.newVal(e.target.value);
},
render: function() {
return (
<div>
<input type="text" onChange={this.handleChange} />
</div>
);
}
});
var App = React.createClass({
getInitialState(){
return {
inputVal: 0
}
},
inputChangedHandler(val) {
console.log(val);
this.setState({inputVal: val});
},
render() {
return(
<div>
<InputComp newVal={this.inputChangedHandler}/>
<h4>{this.state.inputVal}</h4>
</div>
)
}
})
ReactDOM.render(
<App />,
document.getElementById('container')
);
JSFIDDLE
I've made a demo for you here: http://codepen.io/PiotrBerebecki/pen/pEAQzV
The idea is to use the so-called controlled input as defined in the React docs: https://facebook.github.io/react/docs/forms.html#controlled-components
var InputComp = React.createClass({
getInitialState() {
return {
userInput: ''
};
},
onChange(event) {
this.setState({
userInput: event.target.value
});
this.props.newVal(event.target.value);
},
render() {
return (
<div>
InputComp
<input type="text"
value={this.state.userInput}
onChange={this.onChange} />
</div>
);
}
});
var App = React.createClass({
getInitialState() {
return {
inputVal: ''
};
},
inputChangedHandler(valueFromChild) {
console.log('valuefromChild:', valueFromChild);
this.setState({
inputVal: valueFromChild
});
},
render() {
return (
<div>
<InputComp newVal={this.inputChangedHandler}/>
<h4>{this.state.inputVal}</h4>
</div>
);
}
})
ReactDOM.render(
<App />,
document.getElementById('container')
);
You should take the value from the event
inputChangedHandler(e) {
//set user changed value to inputVal
console.log(e.target.value)
},
I thinktThis would be helpful for you.
let InputComp = React.createClass({
getInitialState() {
return {
textVal: "",
};
},
handleChange(e) {
this.setState({ textVal: e.target.value });
this.props.newVal(this.state.textVal);
},
render: function () {
return (
<div>
<input
type="text"
onChange={this.handleChange}
value={this.state.textVal}
/>
</div>
);
},
});
var App = React.createClass({
getInitialState() {
return {
inputVal: 0,
};
},
inputChangedHandler(val) {
this.setState({ inputVal: val });
},
render() {
return (
<div>
<InputComp newVal={this.inputChangedHandler} />
<h4>{this.state.inputVal}</h4>
</div>
);
},
});
ReactDOM.render(<App />, document.getElementById("container"));
I am new to ReactJS, have tried to get the value of the checked/selected checkbox and also date selection from the input type date. but could not able to achieve.
When I click on Generate Report button, you can see the console displaying the states. only the location is getting saved, not the other option.
Here are my functions to update the state values and initial state values:
getInitialState: function() {
return {
selectedLocation: locationList[0].value,
selectedServiceType: [],
selectedStDate:new Date(1446887898),
selectedEdDate:new Date(1446887898)
};
},
selectServiceType:function(e){
selectedTypes.indexOf(e.target.value)? selectedTypes.push(e.target.value):console.log('Already exists in array');
this.setState({
selectedServiceType: e.target.checked
})
},
changeHandler: function(e) {
this.setState({
selectedLocation: e.target.value
})
},
selectStDate: function(e) {
this.setState({
selectedDate: e.target.value
})
},
selectEdDate: function(e) {
this.setState({
selectedEdDate: e.target.value
})
},
The complete Demo here
JSFiddle
Many thanks
I've done refactoring, you can check it, Example
var FulfilmentReport = React.createClass({
getInitialState: function() {
return {
services: this.props.services,
location: this.props.locations[1].value,
startDate: this.formatDate(new Date(1446887898)),
endDate: this.formatDate(new Date(1446887898))
};
},
changeService: function (e) {
var services = this.state.services.map(function (service) {
service.checked = (service.value === e.target.value) ? !service.checked : service.checked;
return service;
});
this.setState({
services: services
});
},
handleChange: function(field, e) {
var data = {};
data[field] = e.target.value;
this.setState(data);
},
render: function() {
var buttonClasess = [
'right', 'mdl-button', 'mdl-js-button', 'mdl-button--raised',
'mdl-js-ripple-effect', 'mdl-button--colored'
].join(' ');
var services = this.state.services.map(function (service) {
return [
<label>{ service.name }</label>,
<input
type="checkbox"
name={service.value}
value={service.value}
checked={service.checked}
onChange={ this.changeService } />
];
}, this)
var locations = this.props.locations.map(function (location, index) {
return (<option key={index} value={ location.value }>{ location.name }</option>);
});
var elements = [{
label: <label>Location</label>,
data: <select
onChange={ this.handleChange.bind(this, 'location') }
value={ this.state.location }>{ locations }</select>
}, {
label: <label>Service Type</label>,
data: <div>{ services }</div>
},{
label: <label>Start Date</label>,
data: <input
type="date"
value={ this.state.startDate }
onChange={ this.handleChange.bind(this, 'startDate') } />
},{
label: <label>'End Date'</label>,
data: <input
type="date"
value={ this.state.endDate }
onChange={ this.handleChange.bind(this, 'endDate') } />
}];
elements = elements.map(function (element) {
return [element.label, element.data];
});
return (<div id="items">
<div>{ elements }</div>
<input type="button" value="Generate Report" onClick={ this.onItemClick } className={ buttonClasess } />
</div>);
},
onItemClick: function() {
this.state.services = this.state.services.filter(function (el) {
return el.checked;
}) ;
console.log( this.state );
},
formatDate: function (date) {
return date.toISOString().slice(0, 10);
}
});
var FilterList = React.createClass({
remove: function(item){
this.props.items = this.props.items.filter(function(itm){
return item.id !== itm.id;
});
return false;
},
render: function() {
var createItem = function(item) {
return (
<li>
<span>{item}</span>
<a href data-id="{item.id}" class="remove-filter" onClick={this.remove.bind(item)}>remove</a>
</li>
);
};
return <ul>{this.props.items.map(createItem.bind(this))}</ul>;
}
});
var FilterApp = React.createClass({
getInitialState: function() {
return {items: [], item: {
id: 0,
type: null
}};
},
onChangeType: function(e){
this.setState({
item: {
id: this.state.items[this.state.items.length],
type: e.target.value
}
});
},
handleSubmit: function(e) {
e.preventDefault();
var nextItems = this.state.items.concat([this.state.item]);
var item = {};
this.setState({items: nextItems, item: {}});
},
render: function() {
return (
<div>
<h3>Filters</h3>
<FilterList items={this.state.items} />
<form className="filter" onSubmit={this.handleSubmit}>
<fieldset>
<legend>Filter</legend>
<div className="form-grp">
<select name="type" onChange={this.onChangeType}>
<option>foo</option>
<option>bar</option>
<option>baz</option>
</select>
</div>
</fieldset>
<div className="actions">
<button>{'Add #' + (this.state.items.length + 1)}</button>
</div>
</form>
</div>
);
}
});
React.render(<FilterApp />, document.body);
I cannot seem to wrap my head around how to remove an item from the list. Probably making a ton of other bad design decisions here too, newbs.
Props on components are immutable, meaning you cannot modify them directly. In your above example if the FilterList component wants to remove an item, it would need to call a callback from the parent component.
A simplified example of this.
FilterApp passes a remove function to FilterList that is called on the onClick event. This will remove an item from the parent, update the state, then cause FilterList to re-render with the new content.
Hope this helps.
Something like the below should work. Let your root component manage state.
var FilterList = React.createClass({
render: function() {
var createItem = function(item) {
return (
<li>
<span>{item}</span>
<a href data-id="{item.id}" class="remove-filter" onClick={this.props.remove.bind(item)}>remove</a>
</li>
);
};
return <ul>{this.props.items.map(createItem.bind(this))}</ul>;
}
});
var FilterApp = React.createClass({
getInitialState: function() {
return {items: [], item: {
id: 0,
type: null
}};
},
onChangeType: function(e){
this.setState({
item: {
id: this.state.items[this.state.items.length],
type: e.target.value
}
});
},
remove: function(item, ev){
ev.preventDefault();
var items = this.state.items.filter(function(itm){
return item.id !== itm.id;
});
this.setState({ items: items });
},
handleSubmit: function(e) {
e.preventDefault();
var nextItems = this.state.items.concat([this.state.item]);
var item = {};
this.setState({items: nextItems, item: {}});
},
render: function() {
return (
<div>
<h3>Filters</h3>
<FilterList remove={this.remove} items={this.state.items} />
<form className="filter" onSubmit={this.handleSubmit}>
<fieldset>
<legend>Filter</legend>
<div className="form-grp">
<select name="type" onChange={this.onChangeType}>
<option>foo</option>
<option>bar</option>
<option>baz</option>
</select>
</div>
</fieldset>
<div className="actions">
<button>{'Add #' + (this.state.items.length + 1)}</button>
</div>
</form>
</div>
);
}
});
React.render(<FilterApp />, document.body);
I am trying to creating some reusable components to filter arrays, but I think I am doing something wrong.
Should I be passing the handleclick all the way back up the chain of components like this?
I also cannot get the loading icon to appear in the filter button, it seems the button only re-renders after the click and filtering has been completed.
Is there a better place to store the active button, but this is the only way I could get the buttons to re-render.
var FilterButton = React.createClass({
getInitialState: function() {
return { loading: false };
},
handleClick: function() {
this.setState({ loading: true }, function() {
this.props.handleClick(this.props.filter);
});
this.setState({ loading: false });
},
render: function() {
var cx = React.addons.classSet;
var classes = cx({
'btn': true,
'btn-white': !this.props.active,
'btn-primary': this.props.active
});
var loader = <i className="fa fa-circle-o-notch fa-spin"></i>;
return (
<button className={classes} onClick={this.handleClick}>
{this.state.loading ? loader : ''} {this.props.label}
</button>
);
}
});
var FilterBar = React.createClass({
getInitialState: function() {
return { filter: 1 };
},
handleClick: function(filter) {
this.setState({ filter: filter }, function() {
this.props.handleClick(this.state.filter);
});
},
render: function() {
var filter = this.state.filter;
return (
<div className="nav">
<FilterButton handleClick={this.handleClick} active={filter == 1} filter="1" label="Pending" />
<FilterButton handleClick={this.handleClick} active={filter == 2} filter="2" label="Canceled" />
<FilterButton handleClick={this.handleClick} active={filter == 3} filter="3" label="Shipped" />
</div>
);
}
});
var OrdersView = React.createClass({
getInitialState: function () {
return {orders: [], status_id: 1};
},
componentDidMount: function() {
/* get orders here via ajax and set state*/
},
handleFilter: function(status_id) {
this.setState({ status_id: status_id });
},
render: function() {
var self = this;
var orders = $.grep(this.state.orders, function(order, i){
return order.status_id == self.state.status_id;
});
return (
<div>
<FilterBar handleClick={this.handleFilter} />
<OrderList orders={orders} />
</div>
);
}
});