Why is a horizontal line created, when user inputs whitespace? - javascript

This is my code. When I'm trying to run it, for empty spaces as input it is creating a horizontal line.
import React, { Component } from 'react';
export default class App extends Component {
constructor(props) {
super(props);
this.state = { items: [], text: '' };
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
render() {
return (
<div>
<form onSubmit = {this.handleSubmit}>
<input
onChange={this.handleChange}
value={this.state.text />
</form>
<div>
<TodoList items={this.state.items} />
</div>
</div>
);
}
handleChange(e) {
this.setState({ text: e.target.value });
}
handleSubmit(e) {
e.preventDefault();
if (!this.state.text.length) {
return;
}
const newItem = {
text: this.state.text,
};
this.setState(prevState => ({
items: prevState.items.concat(newItem),
text: ''
}));
}
}
class TodoList extends React.Component {
render() {
return (
<div>
{this.props.items.map(item => (
<h3 key={item.id}>{item.text}</h3>
))}
</div>
);
}
}

Your code will always append a <h3> element even with whitespace as input.
And you're seeing a horizontal line probably due to the CSS styling applied to
h3.
What you can do it prevent users from inserting whitespace data. One approach is to trim() user's input before doing length checking:
// In handleSubmit()
if (!this.state.text.trim().length) {
return;
}
Now input with only whitespace will become 0 length and therefore exit handleSubmit() earlier.
import React, { Component } from 'react'
class TodoList extends React.Component {
render() {
return (
<div>
{ this.props.items.map(item => <h3 key={ item.id }>{ item.text }</h3>) }
</div>
);
}
}
export default class App extends Component {
constructor(props) {
super(props);
this.state = { items: [], text: '' };
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(e) {
this.setState({ text: e.target.value });
}
handleSubmit(e) {
e.preventDefault();
if (!this.state.text.trim().length) {
return;
}
const newItem = {
text: this.state.text,
};
this.setState(prevState => ({
items: prevState.items.concat(newItem),
text: ''
}));
}
render() {
return (
<div>
<form onSubmit={ this.handleSubmit }>
<input onChange={ this.handleChange } value={ this.state.text }/>
</form>
<div>
<TodoList items={ this.state.items } />
</div>
</div>
)
}
}

Related

React data from Children to Parent, map json

I'm learning ReactJS and I want to map a json in a father component from child search bar. So I got this:
export default class Child extends Component {
constructor(props) {
super(props)
this.state = { data:[], value: '' };
this.handleSubmit = this.handleSubmit.bind(this)
this.handleChange = this.handleChange.bind(this)
}
guardar = (data) => {
this.setState({ data })
this.props.parentCallback({ data })
}
handleChange(e) {
this.setState({ value: e.target.value })
axios.get(`http://localhost:3001/api/search?query=${ e.target.value }`)
.then(( { data } ) => this.guardar(data) )
}
handleSubmit(e) {
e.preventDefault()
}
render() {
return(
<form onSubmit={this.handleSubmit}>
<input type="text"
name='searchbar'
onChange={this.handleChange}/>
</form>
)
}
}
export default class Parent extends Component {
state = {
data: [],
}
handleCallback = (childData) => {
this.setState({
data: childData
})
console.log(this.state.data);
}
render() {
const { data } = this.state
return(
<div>
<SearchBar parentCallback = {this.handleCallback}/>
<ProductCard />
{ [data].map( res => <li key={res.id}>{ res.title }</li>) }
</div>
)
}
}
Here is the result:
I want to map if even if the array is empty, in the console shows me the 50 elements only if I write more than twice in the input and I want them when I reload the page.
Beforehand thank you very much!!

Hide form after submit (but after bringing it back?)

I'm having a hard time making this form submit twice. What do I mean? When I click on submit, the form (on General.js) is hidden and it renders another component (DisplayGeneral.js) displaying the user's input. Then I added a button to bring back the form so the user can edit the information, the problem is that it doesn't toggle again when I click on the form button, you know? What am I missing here? Please, I appreciate any help.
General.js
import React, { Component } from 'react';
import '../style/style.css';
import DisplayGeneral from './DisplayGeneral';
class General extends Component {
constructor(props) {
super(props);
this.state = {
name: '',
showing: true,
isEditing: true,
};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
this.handleClick = this.handleClick.bind(this);
}
handleChange(e) {
const { name, value } = e.target;
this.setState({
[name]: value,
});
}
handleSubmit(e) {
e.preventDefault();
const { showing } = this.state;
this.setState({
showing: !showing,
});
}
handleClick(e) {
e.preventDefault();
const { isEditing } = this.state;
this.setState({
isEditing: !isEditing,
});
}
form = () => {
return (
<div>
<form className='generalForm'>
<label htmlFor='nameInput' className='row'>
Name:{' '}
<input
type='text'
name='name'
value={this.state.name}
onChange={this.handleChange}
id='nameInput'
/>
</label>
<button onClick={this.handleSubmit}>Submit</button>
</form>
</div>
);
};
renderGeneral() {
const {
isEditing,
name,
} = this.state;
return (
<div>
{isEditing ? (
<div>
<DisplayGeneral
handleSubmit={this.handleSubmit}
name={name}
/>
<button onClick={this.handleClick}>Edit</button> // button added
</div>
) : (
this.form()
)}
</div>
);
}
render() {
const { showing } = this.state;
return (
<section className='divGeneral'>
<div className='sectionTitle'>
<h1>General Information</h1>
</div>
{showing ? this.form() : this.renderGeneral()}
</section>
);
}
}
export default General;
DisplayGeneral.js
import React, { Component } from 'react';
class DisplayGeneral extends Component {
render() {
const { name } = this.props;
return (
<section className='renderedSection'>
<article>
<span className='spanArtc'>Name: </span>
{name}
</article>
</section>
);
}
}
export default DisplayGeneral;
If you just want to toggle the form you can keep only one flag isEditing and change it to true, if you want to show the form and false for showing information.
import React, { Component } from 'react';
import '../style/style.css';
import DisplayGeneral from './DisplayGeneral';
class General extends Component {
constructor(props) {
super(props);
this.state = {
name: '',
isEditing: true,
};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
this.handleClick = this.handleClick.bind(this);
}
handleChange(e) {
const { name, value } = e.target;
this.setState({
[name]: value,
});
}
handleSubmit(e) {
e.preventDefault();
this.setState({
isEditing: false,
});
}
handleClick(e) {
e.preventDefault();
this.setState({
isEditing: true,
});
}
form = () => {
return (
<div>
<form className='generalForm'>
<label htmlFor='nameInput' className='row'>
Name:{' '}
<input
type='text'
name='name'
value={this.state.name}
onChange={this.handleChange}
id='nameInput'
/>
</label>
<button onClick={this.handleSubmit}>Submit</button>
</form>
</div>
);
};
renderGeneral() {
const { name } = this.state;
return (
<div>
<DisplayGeneral handleSubmit={this.handleSubmit} name={name} />
<button onClick={this.handleClick}>Edit</button> // button added
</div>
);
}
render() {
const { isEditing } = this.state;
return (
<section className='divGeneral'>
<div className='sectionTitle'>
<h1>General Information</h1>
</div>
{isEditing ? this.form() : this.renderGeneral()}
</section>
);
}
}
export default General;

ReactJS how to access content output from a component?

I'm currently working on a project that uses QuillJS for a rich text editor. I need to post the rich text content to my backend but I'm not sure how to access the QuillJS output.
In RichTextEditor.js
import React, { Component } from "react";
import ReactQuill from "react-quill";
import "react-quill/dist/quill.snow.css";
class RichTextEditor extends Component {
constructor(props) {
super(props);
// this.formats = formats;
this.state = { text: "" }; // You can also pass a Quill Delta here
this.handleChange = this.handleChange.bind(this);
}
handleChange(value) {
this.setState({ text: value });
const text = this.state;
console.log(text);
}
render() {
return (
<ReactQuill
value={this.state.text}
onChange={this.handleChange}
formats={this.formats}
modules={this.modules}
/>
);
}
}
export default RichTextEditor;
The console.log(text) basically just outputs the content of the rich text editor. Something like this "<p><em>aasdasdasd</em><strong><em>asdasdasdasd</em></strong></p>"
In Post.js
import React, { Component } from "react";
import RichTextEditor from "./RichTextEditor.js";
import "../../css/Post.css";
class Post extends Component {
constructor(props) {
super(props);
this.state = {
question: "",
};
}
onChange = (e) => {
this.setState({ [e.target.name]: e.target.value });
console.log(this.state);
};
handleSubmit = (e) => {
e.preventDefault();
const { question } = this.state;
console.log("Question");
console.log(question);
render() {
const { question } = this.state;
return (
<div className="post">
<div className="post__container">
<form onSubmit={this.handleSubmit}>
<div className="post__richTextEditor">
<RichTextEditor value={question} onChange={this.onChange} name="question" />
</div>
</form>
</div>
</div>
);
}
}
export default Post;
I'm trying to update the state of the question but it doesn't seem to be updating. console.log(question) only outputs a single string.
How can I access the same string output from RichTextEditor.js?
Your RichTextEditor component should not handle change, it should only receive props from higher component:
class RichTextEditor extends Component {
constructor(props) {
super(props);
}
render() {
return (
<ReactQuill
value={this.props.value}
onChange={this.props.onChange}
formats={this.formats}
modules={this.modules}
/>
);
}
}
export default RichTextEditor;
Then your Post component pass value and onChange props to RichTextEditor:
class Post extends Component {
constructor(props) {
super(props);
this.state = {
question: "",
};
this.onChange = this.onChange.bind(this);
}
onChange = (e) => {
this.setState({ [e.target.name]: e.target.value });
console.log(this.state);
};
handleSubmit = (e) => {
e.preventDefault();
const { question } = this.state;
console.log("Question");
console.log(question);
render() {
const { question } = this.state;
return (
<div className="post">
<div className="post__container">
<form onSubmit={this.handleSubmit}>
<div className="post__richTextEditor">
<RichTextEditor value={question} onChange={this.onChange} name="question" />
</div>
</form>
</div>
</div>
);
}
}
in RichTextEditor.js
handleChange(value) {
this.setState({ text: value });
const text = this.state;
console.log(text);
props.onChange(text); // passing the inner State to parent as argument to onChange handler
}
Now in Post.js
onChange = (newStateString) => {
//this.setState({ [e.target.name]: e.target.value });
console.log(newStateString); // you should get the string here
};

React JS : grandparent component's setState method doesn't update state of a grandchild input field onChange event click

In the same code, I was able to the get the grandparent component's setState method to update accordingly for an onClick event from the grandchild component, however, for the onChange event, it is failing. I am not getting any errors.
class GrandChild extends React.Component {
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
}
changeNumber=()=> {
this.props.changeNumber();//call child method
}
handleChange(e) {
this.props.onChange(e.target.value);
}
render() {
const data = this.props.data;
return(
<div>
<h1>The number is {this.props.number}</h1>
<input type="text" value = {data} onChange={this.handleChange} />
<button onClick={this.changeNumber}>Increase number by 1</button>
</div>
)
}
}
class Child extends React.Component {
render() {
return(
<div>
<GrandChild number={this.props.number} changeNumber={this.props.changeNumber} value={this.props.data} onChange={this.props.handleChange}/>
</div>
)
}
}
class App extends React.Component {
constructor() {
super()
this.state = {
number: 1,
data: ""
}
this.handleChange = this.handleChange.bind(this);
}
handleChange(data) {
this.setState({data:this.state.data});
console.log(data);
}
changeNumber=()=>{
this.setState((prevState)=>{
console.log(prevState,this.state.data);
return {
number : prevState.number + 1
}
});
}
render() {
const data = this.state.data;
const input = data;
return (
<Child number={this.state.number}
changeNumber = {this.changeNumber}
data={input}
onChange = {this.handleChange}
/>
);
}
}
ReactDOM.render(<App />, document.getElementById('root'));
Console Result:
Object {
data: "",
number: 1
} ""
result screenshot:
console.log result
see code pen for live code:
https://codepen.io/codehorse/pen/yLyEwBw?editors=0011
Your improved code with live demo https://codesandbox.io/s/laughing-sky-kk97b
What need to change <GrandChild number={this.props.number} changeNumber={this.props.changeNumber} value={this.props.data} onChange={this.props.onChange}/>
Complete Code
class GrandChild extends React.Component {
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
}
changeNumber = () => {
this.props.changeNumber(); //call child method
};
handleChange(e) {
this.props.onChange(e.target.value);
}
render() {
const data = this.props.data;
return (
<div>
<h1>The number is {this.props.number}</h1>
<input type="text" value={data} onChange={this.props.onChange} />
<button onClick={this.changeNumber}>Increase number by 1</button>
</div>
);
}
}
class Child extends React.Component {
render() {
return (
<div>
<GrandChild
number={this.props.number}
changeNumber={this.props.changeNumber}
value={this.props.data}
onChange={this.props.onChange}
/>
</div>
);
}
}
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
number: 1,
data: ""
};
}
handleChange = e => {
this.setState({ data: e.target.value });
console.log(e.target.value);
};
changeNumber = () => {
this.setState(prevState => {
console.log(prevState, this.state.data);
return {
number: prevState.number + 1
};
});
};
render() {
const data = this.state.data;
const input = data;
return (
<Child
number={this.state.number}
changeNumber={this.changeNumber}
data={input}
onChange={this.handleChange}
/>
);
}
}
export default App;

how to reset the value of a dropdown to firstvalue after an action is perfomed

I have below simple dropdown component
import React, { Fragment } from 'react';
export default class SimpleDropdown extends React.Component {
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
}
handleChange = (event) => {
this.props.handleSelect(event);
}
render() {
return (
<Fragment>
<select className="dd-wrapper" onChange={this.handleChange}>
{this.props.list.map((item) => (
<option className="dd-list-item" key={item.name} value={item.name}>{item.name}</option>)
)}
</select>
</Fragment>
);
}
}
I'm using this component in some other place as below along with NewMeasureDialogue component.Now,When I select 'Base Measure' from the dropdown and clicked on NewMeasureDialogue 'onYesClicked'.The value from BaseMeasure should be changed to Calculated Measure.
export class ParentComponent {
constructor(props) {
super(props);
this.state = {
measures: [{
name: 'Calculated Measure',
},
{
name: 'Base Measure'
}
]
}
}
handleDropDownSelect = (event) => {
this.setState({
selectedValue: event.target.value,
isBaseMeasure: event.target.value === 'Base Measure' ? true : false
})
}
render() {
return (
<div>
<SimpleDropdown list={this.state.measures} handleSelect={this.handleDropDownSelect} />
<NewMeasureDialogue msg={StringConstants.NEW_MEASURE_DIALOGUE_TEXT} show={this.state.show} close={this.close} onYesClicked={this.onYesClicked} />
</div>
)
}
}
Can someone tell me how to change the dropdownvalue when onYesclicked is performed on NewMeasure Dialogue.
in order to achieve this, you may want to convert your SimpleDropdown into a fully controlled component, meaning it should accept not only handleSelect method, but also a value property
import React, { Fragment } from 'react';
export default class SimpleDropdown extends React.Component {
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
}
handleChange = (event) => {
this.props.handleSelect(event);
}
render() {
return (
<Fragment>
<select className="dd-wrapper" value={this.props.value} onChange={this.handleChange}>
{this.props.list.map((item) => (
<option
className="dd-list-item"
key={item.name}
value={item.name}
>
{item.name}
</option>
))}
</select>
</Fragment>
);
}
}
and do some modification in ParentComponent
export class ParentComponent {
constructor(props) {
super(props);
this.state = {
selectedValue: '',
measures: [{
name: 'Calculated Measure',
},
{
name: 'Base Measure'
}
]
}
}
handleDropDownSelect = (event) => {
this.setState({
selectedValue: event.target.value,
isBaseMeasure: event.target.value === 'Base Measure' ? true : false
})
}
onYesClicked = () => {
this.setState({selectedValue: 'Calculated Measure'})
}
render() {
return (
<div>
<SimpleDropdown
list={this.state.measures}
handleSelect={this.handleDropDownSelect}
value={this.state.selectedValue}
/>
<NewMeasureDialogue
msg={StringConstants.NEW_MEASURE_DIALOGUE_TEXT}
show={this.state.show}
close={this.close}
onYesClicked={this.onYesClicked}
/>
</div>
)
}
}

Categories