Issue with setting input text value to be blank using Refs - javascript

I'm having issues with setting my input text fields to be blank using Refs. You could think of my UI that of a mail inbox app. When I click on the side panel, using the func openIssue() to display the issues in <IssueDetails/> by clicking on an issue from <IssueList/>. My problem is that when I enter values into the input text field. That value is carried on into the next issue's text input value after I click on a new issue in the <IssueList/>.
I've used the following as a guide: Clear an input field with Reactjs?, https://reactjs.org/docs/refs-and-the-dom.html however, what I get hit with is TypeError: Cannot set property 'value' of undefined, how do I over come this?
class App extends Component {
constructor(props) {
super(props);
this.state = {
isLoaded: false,
issues: [],
counter: 0,
selectedIssueId: 0,
currentSection: "inbox",
showIssueBox: true
};
this.sendThru = this.sendThru.bind(this);
}
openIssue(id) {
const issues = this.state.issues;
let copyOfStateIssues = issues.slice();
let modifiedStateWithHighlight = copyOfStateIssues.map(obj => {
if (obj.id !== id) {
obj.highlighted = false;
} else {
obj.highlighted = true;
}
return obj;
});
this.setState({
selectedIssueId: id,
modifiedStateWithHighlight,
issues: modifiedStateWithHighlight
});
this.sendThru();
}
sendThru(el) {
this.inputTitle.value = "";
}
render() {
return (
<div className="App">
{this.state.showIssueBox ? (
<IssueBox
issues={this.state.issues}
selectedIssueId={this.state.selectedIssueId}
onIssueSelected={id => {
this.openIssue(id);
}}
inputRef={el => (this.inputTitle = el)}
/>
) : (
<div />
)}
</div>
);
}
}
class IssueBox extends Component {
render() {
const currentIssue = this.props.issues.find(
x => x.id === this.props.selectedIssueId
);
return (
<div className="wrapper">
<div className="inbox-container">
<IssueList
issues={this.props.issues}
onIssueSelected={this.props.onIssueSelected}
selectedIssueId={this.props.selectedIssueId}
/>
<IssueDetails
issues={this.props.issues}
issue={currentIssue}
onInputRef={this.props.inputRef}
/>
</div>
</div>
);
}
}
class IssueDetails extends Component {
constructor(props) {
super(props);
this.state = {
currentPage: 1,
urlsPerPage: 5,
activeItem: 0
};
}
render() {
const issueDummy = currentURLs.map((obj, i) => {
const noIssueID = (
<input
ref={this.props.onInputRef}
type="text"
onChange={this.props.onInputUpdate.bind(this, obj)}
/>
);
return (
<tr role="row" key={i}>
<td role="cell" style={td4Styles}>
{issue.verified === true ? hasIssueID : noIssueID}
</td>
</tr>
);
});
return (
<div className="issue-content">
<div className="issue-content__message">
<div className="url_div_container">
<form
onSubmit={this.props.onVerifiationSubmission.bind(this, issue)}
>
<table>
<tbody className="group-row">{issueDummy}</tbody>
</table>
</form>
</div>
</div>
</div>
);
}
}
My goal is to clear the text input field of the previously entered after I click on a new issue from <IssueList>, which is triggered by openIssue(). Thus rendering a new set of issues and text input field for < IssueDetails>

Related

how to add or remove tables dynamically in ReactJS

i want to add a table row by clicking Add, and remove a table row by clicking the small red div inside the table, while retaining the color change option when table is clicked on.
I've been trying for hours, but i'm still new to ReactJS, maybe someone could give me a hint, how to do this, for example with help of an array, a boolean or a for loop? I can't get the right way yet, would be thankful for your input.
i've been thinking about this kind of logic, but haven't been able to implement it yet..
{Boolean(this.state.rows.length) && (
<div onClick={this.handleRemoveRow}></div>
)}
https://jsfiddle.net/mattighof/0uop13kd/
Do the following:
Maintain a state say list and store all your items
Create onClick handlers for adding and removing items in the table
update the state when you add/remove
iterate and render this.state.list
Make sure to do event.stopPropagation() in the remove handler. this way your colour change functionality still works.
See here the implementation of adding and removing item
Code Snippet:
class Table extends React.Component {
constructor(props) {
super(props);
this.state = {
tableColor: true,
list: []
};
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
this.setState({
tableColor: !this.state.tableColor
});
}
addItem() {
this.setState({ list: this.state.list.concat("item") });
}
removeItem(e, index) {
e.stopPropagation();
this.setState({ list: this.state.list.filter((_, i) => index !== i) });
}
render() {
return (
<div className="container">
<button onClick={this.addItem} type="button">
Add
</button>
<table>
{this.state.list.map((item, index) => {
return (
<tr>
<td
className={this.state.tableColor ? "trRed" : "trBlack"}
onClick={this.handleClick}
>
{item}
<div
onClick={e => this.removeItem(e, index)}
className="innerDiv"
/>
</td>
</tr>
);
})}
</table>
</div>
);
}
}
This is one of the ways you can do it:
class Table extends React.Component {
constructor(props){
super(props)
this.state ={
rows:[{id:8,name:'item8',tablecColor:'trBlack'}],
tableColor: true
}
this.handleClick = this.handleClick.bind(this);
this.handleAdd = this.handleAdd.bind(this);
this.renderRows = this.renderRows.bind(this);
}
handleClick(clickedRow){
const {rows} = this.state;
let newRows = rows.map(row => {
if(row.id === clickedRow.id) {
row.tableColor = 'trRed'
return row
}
return row;})
this.setState({rows:newRows})
}
handleAdd() {
const {rows} = this.state;
const count = rows.length;
rows.push({id:count,name:count,tablecColor:'trBlack'})
this.setState({rows:rows})
}
renderRows() {
return this.state.rows.map(row => {
return (<tr>
<td className={row.tableColor}>
<div>{row.name}
<div onClick={() => this.handleClick(row)}
className="innerDiv">
</div>
</div>
</td>
</tr>)
});
}
render(){
return (
<div className="container">
<button type="button">Add</button>
<table>
{this.renderRows()}
</table>
</div>
)
}
}
ReactDOM.render(<Table />, document.querySelector("#app"));

how fix selected permanently ReactJS

I would like to explain my problem of the day.
the code works correctly ,
the only problem is
when i click on my navbar to select a tab ,
my activeclassname works fine except that when i click elsewhere on the same page i lose my activeclassname
I would like him to be active permanently
Do you have an idea of how to fix this?
class MainHome extends Component {
constructor(props) {
super(props);
this.state = {
};
// preserve the initial state in a new object
this.toggle = this.toggle.bind(this);
this.cgtChange1= this.cgtChange1.bind(this);
this.cgtChange2= this.cgtChange2.bind(this);
}
cgtChange1() {
console.log('bière clicked')
this.setState({
cgt : 1
})
}
cgtChange2() {
console.log('cocktails clicked')
this.setState({
cgt :2
})
}
render() {
let addedItems = this.props.items.length ?
(
this.props.items.filter(item => item.ctg === this.state.cgt).map(item => {
return (
<div key={item.id}>
{item.title}
</div>
)
})) :
(
<div></div>
)
return (
<div>
<Header text='Carte'/>
<NavBar
onClick1={this.cgtChange1}
onClick2={this.cgtChange2}
/>
{addedItems}
</div>
)
}
}
NavBar
export default class FocusOnSelect extends Component {
render() {
return (
<div>
<button onClick={this.props.onClick1}
activeClasseName="selected" className='inactive' > Bières
</button>
</div>
<div >
<button onClick={this.props.onClick2} activeClasseName="selected" className='inactive' > Cocktails </button>
</div>
</div>
);
}
}

Hiding An Element While User Input Doesn't Exist

My goal is to hide one of my divs or all my p tags until user input actually exists. You can see my attempt below which included a method to change the value of my div state to true or false and whether it's true or false, adjust the display to block or none whether or not the user has inputted anything.
I understand that it would be simple to apply this to a button of some sort but my goal here is to allow React to re-render the div or p elements once the user has typed something in.
My vision was to measure the user input's length, and if it was greater than 0, show my div or p tags.
Within my render section of my code, you'll see a div with three p tags inside. I want those p tags, or even the entire div (if it's easier) to not show until the user starts typing something within the input box.
import React from "react";
class UserInput extends React.Component {
constructor(props) {
super(props);
this.state = {
value: "",
showElements: false
};
}
handleChange = event => {
this.setState({ value: event.target.value });
};
badRobot = () => {
const newInput = this.state.value;
let badInput = "BLA"
.repeat(newInput.length / 3 + 1)
.substring(0, newInput.length);
return badInput;
};
hideElements = () => {
const userValueLength = this.state.value;
if (userValueLength.length !== 0) {
console.log("it worked");
this.setState({ showElements: true });
}
};
render() {
return (
<div>
<form>
<label>
<p>Say Anything</p>
<input
type="text"
value={this.state.value}
onChange={this.handleChange}
/>
</label>
</form>
<div style={{ display: this.state.showElements ? "block" : "none" }}>
<h3>Good Robot</h3>
<p>I hear you saying {this.state.value}. Is that correct?</p>
<h3>Bad Robot</h3>
<p>I hear you saying {this.badRobot()}. Is that correct?</p>
<h3>Kanyebot 5000</h3>
<p>I'm gonna let you finish but Beyonce is {this.state.value}.</p>
</div>
</div>
);
}
}
export default UserInput;
Checking if the value string differs from the empty string sounds like a good condition for showing the div.
Instead of keeping a boolean in state you could check the value directly in the render method.
class UserInput extends React.Component {
state = {
value: ""
};
handleChange = event => {
this.setState({ value: event.target.value });
};
render() {
const { value } = this.state;
const showDiv = value !== "";
const badInput = "BLA"
.repeat(value.length / 3 + 1)
.substring(0, value.length);
return (
<div>
<form>
<label>
<p>Say Anything</p>
<input
type="text"
value={value}
onChange={this.handleChange}
/>
</label>
</form>
<div style={{ display: showDiv ? "block" : "none" }}>
<h3>Good Robot</h3>
<p>I hear you saying {value}. Is that correct?</p>
<h3>Bad Robot</h3>
<p>I hear you saying {badInput}. Is that correct?</p>
<h3>Kanyebot 5000</h3>
<p>I'm gonna let you finish but Beyonce is {value}.</p>
</div>
</div>
);
}
}
ReactDOM.render(<UserInput />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root"></div>
You can do conditional rending.
class UserInput extends React.Component {
constructor(props) {
super(props);
this.state = {
value: '',
showElements: false
};
}
handleChange = (event) => {
const value = event.target.value;
const showElements = value.length > 0 ? true: false;
this.setState({showElements, value});
}
badRobot = () => {
const newInput = this.state.value;
let badInput = 'BLA'.repeat(newInput.length / 3 + 1).substring(0, newInput.length)
return badInput
}
hideElements = () => {
const userValueLength = this.state.value
if (userValueLength.length !== 0) {
console.log("it worked");
this.setState({showElements: true})
}
}
render(){
return(
<div>
<form>
<label>
<p>Say Anything</p>
<input type="text" value={this.state.value} onChange={this.handleChange} />
</label>
</form>
{
this.state.showElements ?
(
<div>
<h3>Good Robot</h3>
<p>I hear you saying {this.state.value}. Is that correct?</p>
<h3>Bad Robot</h3>
<p>I hear you saying {this.badRobot()}. Is that correct?</p>
<h3>Kanyebot 5000</h3>
<p>I'm gonna let you finish but Beyonce is {this.state.value}.</p>
</div>
): null
}
</div>
)
}
}

React list choosing option

I have an location app which can save name of locations.
I am trying to get each saved location a red border by clicking on it.
What it does is changing the border color of all the categories.
How can I apply that?
class Categories extends Component {
constructor(props) {
super(props);
this.state = {
term: '',
categories: [],
selectedCategories: [],
hidden: true,
checkboxState: true
};
}
toggle(e) {
this.setState({
checkboxState: !this.state.checkboxState
})
}
onChange = (event) => {
this.setState({ term: event.target.value });
}
addCategory = (event) => {
if (this.state.term === '') {
alert('Please name your category!')
} else {
event.preventDefault();
this.setState({
term: '',
categories: [...this.state.categories, this.state.term]
});
}
}
render() {
return (
<div className="categories">
<h1>Categories</h1>
<div className='actions'>
<button className="delete" onClick={this.deleteCategory}>Delete</button>
<button className="edit" onClick={this.editCategory}>Edit</button>
</div>
<p>To add new category, please enter category name</p>
<form className="App" onSubmit={this.addCategory}>
<input value={this.state.term} onChange={this.onChange} />
<button>Add</button>
</form>
{this.state.categories.map((category, index) =>
<button
key={index}
style={this.state.checkboxState ? { borderColor: '' } : { borderColor: 'red' }}
checked={this.state.isChecked}
onClick={this.toggle.bind(this)}>
{category}</button>
)}
</div >
);
}
}
I want to be able to control each selected category seperatly, to be able to delete and edit theme as well.
You can set the state based on index and retrieve the similar way,
Code:
{this.state.categories.map((category, index) =>
<button
key={index}
id={`checkboxState${index}`}
style={!this.state[`checkboxState${index}`] ?
{ borderColor: '' } : { border: '2px solid red' }}
checked={this.state.isChecked}
onClick={this.toggle}>
{category}</button>
)}
You can see how I am checking the state dynamically this.state[`checkboxState${index}`] and also I have assigned an id to it.
In toggle method:
toggle = (e) => {
const id = e.target.id;
this.setState({
[id]: !this.state[id]
})
}
FYI, this is a working code, you can see it
https://codesandbox.io/s/vy3r73jkrl
Let me know if this helps you :)
Here's a really bad example using react. I'd more than likely use this.props.children instead of just cramming them in there. This would allow it to be more dynamic. And instead of using state names we could then just use indexes. But you'll observe, that the parent container decides which child is red by passing a method to each child. On click, the child fires the method from the parent. How you implement it can vary in a million different ways, but the overall idea should work.
class ChildContainer extends React.Component
{
constructor(props)
{
super(props);
}
render() {
let color = this.props.backgroundColor;
return(
<section
className={'child'}
style={{backgroundColor: color}}
onClick={this.props.selectMe}
>
</section>
)
}
}
class Parent extends React.Component
{
constructor(props)
{
super(props)
this.state = {
first : 'Pink',
second : 'Pink',
third : 'Pink',
previous: null
}
this.updateChild = this.updateChild.bind(this);
}
updateChild(name)
{
let {state} = this;
let previous = state.previous;
if(previous)
{
state[previous] = 'Pink';
}
state[name] = 'Red';
state.previous = name;
this.setState(state);
}
render()
{
console.log(this)
return(
<section id={'parent'}>
<ChildContainer
selectMe={() => this.updateChild('first')}
backgroundColor = {this.state.first}
/>
<ChildContainer
selectMe={() => this.updateChild('second')}
backgroundColor = {this.state.second}
/>
<ChildContainer
selectMe={() => this.updateChild('third')}
backgroundColor = {this.state.third}
/>
</section>
)
}
}
class App extends React.Component
{
constructor(props)
{
super(props)
}
render()
{
return(
<section>
<Parent/>
</section>
)
}
}
React.render(<App />, document.getElementById('root'));
You need to track the state of every checkbox, possibly have an array with all currently checked checkboxes.
Then instead of this.state.checkboxState in this.state.checkboxState ? { borderColor: '' } : { borderColor: 'red' } you need to check if current category is in the currently checked categories array.
Hope this helps

Getting value from react component

I have a component InputArea with state = {input: ''}
Then I map several of these components in a container and write them in state = {inputAreas: []}
Now, how can I get inputs in the container? Logging this.state.inputAreas[0] returns object like this:
{$$typeof: Symbol(react.element), type: ƒ, key: "1", ref: null, props:
{…}, …}
In elements it shows like this:
<input type="text" class="form-control" name="input" value="abc">
Using this.state.prefooterArea[0].value gives undefined.
I also tried passing input from component to container as props, but it says getInput is not a function. From what I understood it has something to do with the fact I used map in the container. I can't use redux in this project.
Code of component
class PrefooterAreaInput extends Component {
state = {
input: ''
}
textChangedHandler = (event) => {
let newState = {};
newState[event.target.name] = event.target.value;
this.setState(newState);
}
render() {
return (
<div>
<input
className="form-control"
type="text"
name="input"
value = {this.state.input}
onChange={this.textChangedHandler}
/>
</div>
)
}
}
Code of container
class DescriptionFrame extends Component {
state = {,
prefooterArea: [<PrefooterAreaInput key={1}/>]
};
addFooterInputHandler = event => {
event.preventDefault();
if (this.state.prefooterArea.length < prefooterInputFieldsMax) {
var newPrefooterArea = this.state.prefooterArea.map(
inputField => inputField
);
newPrefooterArea.push(
<PrefooterAreaInput key={this.state.prefooterArea.length + 1} />
);
this.setState({ prefooterArea: newPrefooterArea });
}
};
removeFooterInputHandler = event => {
event.preventDefault();
if (this.state.prefooterArea.length > 1) {
var newPrefooterArea = this.state.prefooterArea.map(
inputField => inputField
);
newPrefooterArea.splice(newPrefooterArea.length - 1);
this.setState({ prefooterArea: newPrefooterArea });
}
render() {
// want to get this.state.prefooterArea[0]'s value
return (
<div>
{this.state.prefooterArea}
<a
className="nav-link"
href=""
onClick={this.addFooterInputHandler}
>
Add More
</a>
<a
className="nav-link"
href=""
onClick={this.removeFooterInputHandler}
>
Remove Last
</a>
</div>
);
}
}
Figured it out. This caused problem.
prefooterArea: [<PrefooterAreaInput key={1}/>]
I should have added that initial PrefooterAreaInput with lifecycle method instead. With that I was able to pass state just fine.
Are you trying to achieve something like this ?
child component :
export default class InputBox extends React.Component {
render() {
return (
<input onChange={event => this.props.onChange(event.target.value)} />
);
}}
parent component :
import InputBox from './InputBox';
class FilterBar extends React.Component {
constructor(props) {
super(props);
this.state = {
inputs: "" //get input value from state this input
};
this.updateFilters = this.updateFilters.bind(this);
}
updateFilters(i) {
this.setState({ inputs: i }); // this will print whatever input you type
}
render() {
return (
<div>
<InputBox onChange={(i) => this.updateFilters(i)} />
</div>
);
}
}

Categories

Resources