inputs mapped from object update onChange React.JS - javascript

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

Related

button not working in React

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

React render has the correct data but won't render the JSX

So, I believe this is a formatting issue OR I'm not clear about how the return works when dynamically building.
The render function in Results works, if I replace the code with anythign else it renders where I want. Similarly, the console.log's in the Results function outputs the data correctly. There's no error, it just doesn't render the html and it doesn't hit the debugger in SynonymElement.
What am I missing in here / what core concept am I misconstruing?
(This is just an input form that takes a word, user hits submit, it returns an object with the word as a key and the value an array of synonynms. that get rendered in the ul)
'use strict'
const Smithy = React.createClass({
dsiplayName: "Smithy",
getInitialState: function() {
return { data: []};
},
handleSubmit: function(data) {
$.get('/get-synonyms', { data: data.data }).done(function(data) {
this.setState({ data: data})
}.bind(this));
},
render: function() {
return (
<div className="smithy">
<h1>Craft Tweet</h1>
<SmithyForm onSubmit={this.handleSubmit} />
<Results data={this.state.data} />
</div>
)
}
})
const SmithyForm = React.createClass({
displayName: "SmithyForm",
getInitialState: function() {
return { placeholder: "tweet", value: "" };
},
handleChange: function(event) {
this.setState({value: event.target.value});
},
handleSubmit: function(event) {
event.preventDefault();
var tweet = this.state.value.trim();
this.props.onSubmit({ data: tweet });
this.setState({value: ''});
},
render: function() {
var placeholder = this.state.placeholder;
var value = this.state.value;
return (
<form className="smithyForm" onSubmit={this.handleSubmit}>
<input type="text" placeholder={placeholder} value={value} onChange={this.handleChange} />
<button>smithy</button>
</form>
);
}
})
const SynonymElement = React.createClass({
render: function() {
debugger
return (
<li>{this.props.data}</li>
)
}
})
const Results = React.createClass({
render: function() {
var words = this.props.data;
return (
<div className="results">
{
Object.keys(words).map(function(value) {
{ console.log(value) }
<div className={value}>
<ul>
{
words[value].map(function(syn) {
{ console.log(syn) }
return <SynonymElement data={syn} />
})
}
</ul>
</div>
})
}
</div>
)
}
})
ReactDOM.render(<Smithy />, document.getElementsByClassName('container')[0])
Might have some other complicating issues but assuming everything else is wired up correctly, you need to return the result of the function you pass into the first map (over the collection Object.keys(words)) just as you have for the later map otherwise the function is executed and nothing useful is returned.
Possibly just a dupe of loop inside React JSX
return (
<div className="results">
{
Object.keys(words).map(function(value) {
return ( // <-- this
<div className={value}>

ReactJs Checkbox value and date not getting updated in state

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

React - State not updated

Here I try to set state.autocomplete to 'hello' and then print it, but state seems to be null. How can that be when I just updated the state using setState? data is set as a global variable.
var data = {
populate_at: ['web_start', 'web_end'],
autocomplete_from: ['customer_name', 'customer_address']
};
var AutocompleteFromCheckboxes = React.createClass({
handleChange: function(e) {
this.setState( { autocomplete_from: 'event.target.value' } );
console.log('autocompleteFrom state: ', this.state.autocomplete_from);
// ^ => Uncaught TypeError: Cannot read property 'autocomplete_from' of null
return 1;
},
render: function() {
var autocompleteFrom = this.props.autocomplete_from.map(function(value) {
return (
<label for={value}>
<input type="checkbox" name={value} value="{value}"
onChange={this.handleChange.bind(this)}
ref="autocomplete-from"/>
{value}
</label>
);
}, this);
return (
<div className="autocomplete-from">
{autocompleteFrom}
</div>
);
}
});
var DynamicForm = React.createClass({
getInitialState: function() {
return {
name : null,
populate_at : null,
same_as : null,
autocomplete_from : "not set",
title : null
};
},
saveAndContinue: function(e) {
e.preventDefault();
var data = {
name : this.refs.name.getDOMNode().value,
};
console.log('data: ' + data.name);
},
render: function() {
return (
<AutocompleteFromCheckboxes
autocomplete_from={this.props.data.autocomplete_from} />
);
}
});
var mountpoint = document.getElementById('dynamic-form');
if ( mountpoint ) {
React.render(<DynamicForm data={data} />, mountpoint);
}
});
From the reactjs docs:
setState() does not immediately mutate this.state but creates a pending state transition. Accessing this.state after calling this method can potentially return the existing value.
https://facebook.github.io/react/docs/component-api.html
What you can do is pass a callback function to setState which is triggered once the state has been updated:
this.setState(
{autocomplete_from: ...},
function () {
... at this point the state of the component is set ...
}
)
You need to set the initial state of your component, try adding the following to the top of your component.
getInitialState: function() {
return {
autocomplete_from: ''
};
}
EDIT:
In your DynamicFrom component you have:
render: function() {
return (
<AutocompleteFromCheckboxes
autocomplete_from={this.props.data.autocomplete_from} />
);
}
Since you are trying to reference the state you should write
autocomplete_form={this.state.autocomplete_from}
Also you are trying to set the state from a child component and it should not directly modify state. The best way to approach this is to pass down a function from DynamicFrom(holds the state) to AutocompleteFromCheckboxes. Like so.
var DynamicForm = React.createClass({
handleChange: function(value) {
this.setState({autocompelete_from: value});
},
render: function() {
return(
<AutocompleteFromCheckboxes
autocomplete_from={this.state.autocomplete_from}
handleChange={this.handleChange}
/>
);
},
....
});
Then call that function in your child component
AutocompleteFromCheckboxes = React.createClass({
....
onChange={this.handleChange}
....
handleChange: function(e) {
this.props.handleChange(e.target.value);
}
});
To see updated state value after doing setState you should do something like below
this.setState( { autocomplete_from: 'event.target.value' }, () => {
console.log(this.state.autocomplete_from);//this will print the updated state value
});

how to remove an item from a list with a click event in ReactJS?

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

Categories

Resources