React toggle checkbox not toggling - javascript

I am trying to wrap content in my React app to use a different top-level element.
In my state I have defined wrapContent: false
I have defined a toggleWrap method.
toggleWrap = () => {
this.setState(state => state.wrapContent = !state.wrapContent);
}
And finally in my input checkbox I have included the toggleWrap method in
onChange={this.toggleWrap}
Unfortunately when I run my code, pressing on the checkbox does not wrap my component content in the following code inside my wrapContent method
wrapContent(content){
return this.state.wrapContent
? <div className="bg-secondary p-2">
<div className="bg-light"> {content} </div>
which wraps the contents of my render(){} return in this component.
What is strange is that when I manually change wrapContent: false in my state to True, I see that the checkbox is checked in my browser and that the code within my render is properly wrapped.
So it seems that just my toggleWrap function is not working as it should.
Could someone help here?
Full code:
import React, { Component } from 'react'
import { ValidationDisplay } from './ValidationDisplay';
import { GetValidationMessages } from './ValidationMessages';
export class Editor extends Component {
constructor(props) {
super(props);
this.formElements = {
name: { label: "Name", name: "name", validation: { required: true, minLength: 3 } },
category: { label: "Category", name: "category", validation: { required: true, minLength: 5 } },
price: { label: "Price", name: "price", validation: { type: "number", required: true, min: 5 } }
}
this.state = {
errors: {},
wrapContent: false
}
}
// 06.11.21- method is invoked when the content is rendered
setElement = (element) => {
if (element !== null) {
this.formElements[element.name].element = element;
}
}
// handleChange = (event) => {
// event.persist()
// this.setState(state => state[event.target.name] = event.target.value);
// }
handleAdd = () => {
if (this.validateFormElements()) {
let data = {};
Object.values(this.formElements)
.forEach(v => {
data[v.element.name] = v.element.value;
v.element.value = "";
});
this.props.callback(data);
this.formElements.name.element.focus();
}
}
validateFormElement = (name) => {
let errors = GetValidationMessages(this.formElements[name].element);
this.setState(state => state.errors[name] = errors);
return errors.length === 0;
}
validateFormElements = () => {
let valid = true;
Object.keys(this.formElements).forEach(name => {
if (!this.validateFormElement(name)) {
valid = false;
}
})
return valid;
}
toggleWrap = () => {
this.setState(state => state.wrapContent = !state.wrapContent);
}
wrapContent(content) {
return this.state.wrapContent
? <div className="bg-secondary p-2">
<div className="bg-light"> {content} </div>
</div>
: content;
}
render() {
return this.wrapContent(
<React.Fragment>
<div className="form-group text-center p-2">
<div className="form-check">
<input className="form-check-input"
type="checkbox"
checked={this.state.wrapContent}
onChange={this.toggleWrap} />
<label className="form-check-label">Wrap Content</label>
</div>
</div>
{
Object.values(this.formElements).map(elem =>
<div className="form-group p-2" key={elem.name}>
<label>{elem.label}</label>
<input className="form-control"
name={elem.name}
autoFocus={elem.name === "name"}
ref={this.setElement}
onChange={() => this.validateFormElement(elem.name)}
{...elem.validation} />
<ValidationDisplay
errors={this.state.errors[elem.name]} />
</div>)
}
<div className="text-center">
<button className="btn btn-primary" onClick={this.handleAdd}>
Add
</button>
</div>
</React.Fragment>)
}
}

This was an issue with how you update the state
Try below
toggleWrap = () => {
this.setState({ wrapContent: !this.state.wrapContent });
};
or
toggleWrap = () => {
this.setState((state) => {
return { ...state, wrapContent: !this.state.wrapContent };
});
};
instead of
toggleWrap = () => {
this.setState(state => state.wrapContent = !state.wrapContent);
}

Related

State won't update

I'm working on order system for my portfolio and I need your help.
for some reason one of the state values won't update while other does.
state = {
currOrder: {
createdAt: Date.now(),
totalPrice: 0,
lastUpdated: Date.now(),
notes: '',
products: [],
miniClient: {
_id: '',
fullName: ''
}
},
client: this.props.client
}
componentDidMount() {
if (this.props.currOrder) {
const currOrder = this.props.currOrder
this.setState({ currOrder })
} else {
this.setState({ currOrder: { ...this.state.currOrder, miniClient: { _id: this.state.client._id, fullName: this.state.client.fullName } } })
}
}
onHandleChange = (ev) => {
if (ev.target) {
const { target } = ev
const field = target.name
const value = target.type === 'number' ? +target.value : target.value
this.setState((prevState) => ({ currOrder: { ...prevState.currOrder, [field]: value } }))
}
}
getOrderLastUpdate = () => {
const updateDate = Date.now()
this.setState({ currOrder: { ...this.state.currOrder, lastUpdated: updateDate } }, () => { console.log(this.state.currOrder) })
}
onSubmitOrder = () => {
const { currOrder } = this.state
if (!currOrder._id) {
this.props.addOrder(currOrder)
this.props.isEditModalOpen()
} else {
this.getOrderLastUpdate()
this.props.updateOrder(currOrder)
this.props.isEditModalOpen()
}
}
render() {
const { notes, totalPrice, lastUpdated } = this.state.currOrder
const { client } = this.props
return (
<div className="order-edit">
<div>{client.fullName}</div>
<div>{utilService.formattedDates(lastUpdated)} : עודכן לאחרונה</div>
<div className="order-edit-info-holder">
<input type="number"
name="totalPrice"
value={totalPrice}
onChange={this.onHandleChange} />
<label htmlFor="totalPrice">מחיר</label>
</div>
<div className="order-edit-info-holder">
<input type="text"
name="notes"
value={notes}
onChange={this.onHandleChange} />
<label htmlFor="totalPrice">הערות</label>
</div>
<div className="order-edit-btns-container">
<button onClick={this.onSubmitOrder}>שמור</button>
<button onClick={this.props.isEditModalOpen}>בטל</button>
</div>
</div>
)
}
for some reason it refuses to update the lastUpdated value (as all other values are working fine :-()
Am I doing something wrong?
as for now the CB for getOrderLastUpdate function (console.log) won't even work.

Reset table using reset button

I'm new React developer(mainly with hooks but did not find good example with hooks), here i have antd table with search functionality, my question is when user writes something in search then user gets different result, how to cancel that search by clicking 'Reset' button ?
my code:
https://codesandbox.io/s/antd-table-filter-search-forked-mqhcn?file=/src/EventsSection/EventsSection.js
You can add an id to your input into TitleSearch.js:
<Search
id='IDYOUWANT'
placeholder="Enter Title"
onSearch={onSearch}
onChange={onChange}
style={{ width: 200 }}
/>
And add event into EventsSection.js
ResetInput = () => {
const input = document.getElementById('IDYOUWANT');
input.value = '';
this.handleSearch('');
}
....
<button
onClick={this.ResetInput}
>Reset</button>
Change IDYOUWANT with your id
run this code
Created a new function for reset value and trigger it from reset button.
function:
resetValue = () =>{
this.setState({
eventsData: eventsData
});
}
And trigger from button
<button onClick={this.resetValue}>Reset</button>
all code::
import React, { Component } from "react";
import styles from "./style.module.css";
import { EventsTable } from "../EventsTable";
import { StatusFilter } from "../StatusFilter";
import { TitleSearch } from "../TitleSearch";
const eventsData = [
{
key: 1,
title: "Bulletproof EP1",
fileType: "Atmos",
process: "match media",
performedBy: "Denise Etridge",
operationNote: "-",
updatedAt: "26/09/2018 17:21",
status: "complete"
},
{
key: 2,
title: "Dexter EP2",
fileType: "Video",
process: "Compliance",
performedBy: "Dane Gill",
operationNote: "passed",
updatedAt: "21/09/2018 12:21",
status: "inProgress"
}
];
class EventsSection extends Component {
constructor(props) {
super(props);
this.state = {
eventsData
};
}
handleFilter = (key) => {
const selected = parseInt(key);
if (selected === 3) {
return this.setState({
eventsData
});
}
const statusMap = {
1: "complete",
2: "inProgress"
};
const selectedStatus = statusMap[selected];
const filteredEvents = eventsData.filter(
({ status }) => status === selectedStatus
);
this.setState({
eventsData: filteredEvents
});
};
handleSearch = (searchText) => {
const filteredEvents = eventsData.filter(({ title }) => {
title = title.toLowerCase();
return title.includes(searchText);
});
this.setState({
eventsData: filteredEvents
});
};
handleChange = (e) => {
const searchText = e.target.value;
const filteredEvents = eventsData.filter(({ title }) => {
title = title.toLowerCase();
return title.includes(searchText);
});
this.setState({
eventsData: filteredEvents
});
};
resetValue = () =>{
this.setState({
eventsData: eventsData
});
}
render() {
return (
<section className={styles.container}>
<header className={styles.header}>
<h1 className={styles.title}>Events</h1>
<button onClick={this.resetValue}>Reset</button>
<TitleSearch
onSearch={this.handleSearch}
onChange={this.handleChange}
className={styles.action}
/>
</header>
<EventsTable eventsData={this.state.eventsData} />
</section>
);
}
}
export { EventsSection };
Here is what i did in order to solve it:
i added onClick on the button
<button onClick={this.resetSearch}>Reset</button>
Then in the function i put handleSearch to '', by doing this it reset the table:
resetSearch = () =>{
this.handleSearch('')
}

My forEach statement is repeating more than it should

I am using firebase and react js. my forEach loop is only supposed to repeat for the number of objects I have stored in the firebase database but instead of repeated the expected 3 times it will repeat 8 or 9 or something like that. Also when I run the code a second time it will repeat super fast and fill up my console.
constructor() {
super()
this.state = {
warmupList: [],
title: "",
id: ""
}
}
handleInputChange = (e) => {
this.setState({
title: e.target.value
})
}
SetActiveWarmup(id) {
const warmupRef = firebase.database().ref("Warmups")
warmupRef.on("value",(snapshot) => {
const warmups = snapshot.val()
this is where the for each is
Object.keys(warmups).forEach(key => {
if(id === key) {
warmupRef.child(key).update({
activity: "True"
})
} else {
warmupRef.child(key).update({
activity: "False"
})
}
console.log("has run")
})
})
}
createWarmup = (e) => {
e.preventDefault()
if(this.state.title === "") return
const warmupRef = firebase.database().ref("Warmups")
var key = warmupRef.push().key
warmupRef.child(key).set({
title: this.state.title,
activity: "True",
id: key
})
this.setState({
title: ""
})
}
componentWillMount() {
this._isMounted = true;
const warmupRef = firebase.database().ref("Warmups")
warmupRef.on("value",(snapshot) => {
const warmups = snapshot.val()
const warmupList = []
for(let id in warmups) {
warmupList.push(warmups[id])
}
this.setState({
warmupList: warmupList
})
})
}
render() {
return (
<div className={`warmup${this.props.activity}`}>
<div className="newWarmup__bottom">
<form onSubmit={this.createWarmup}>
<input placeholder="My Warmup..."
value={this.state.title}
onChange={this.handleInputChange} />
<CircleButton click={this.createWarmup}
Icon={AddIcon} color="Green" />
</form>
</div>
<div className="warmup__select">
{this.state.warmupList.map(warmup =>
<SelectWarmup key={v4()}
text={warmup.title}
activity={warmup.activity}
click={() => this.SetActiveWarmup(warmup.id)} />
)}
</div>
</div>
)
}
}

Could not check the input value properly using React.js

I need to check the user input value using React.js but its not working as expected. I am explaining my code below.
import React, { Component } from "react";
import TodoItems from "./TodoItems";
import "./TodoList.css";
class TodoList extends Component {
constructor(props, context){
super(props, context);
this.state={
items:[]
}
this.listOfKeyWords = ["script", "embed", "object", "iframe"];
this.addItem=this.addItem.bind(this);
this.deleteItem = this.deleteItem.bind(this);
this.editItem = this.editItem.bind(this);
}
addItem(e){
e.preventDefault();
if(this.state.editKey){
this.saveEditedText();
return;
}
let maliciousStr = this.listOfKeyWords.find(tag => {
return this.inputElement.value.toLowerCase().indexOf(tag) !== -1;
});
if (!maliciousStr) {
var itemArray = this.state.items;
if (this.inputElement.value !== '') {
itemArray.unshift({
text:this.inputElement.value,
key:Date.now()
})
this.setState({
items:itemArray
})
this.divRef.insertAdjacentHTML("beforeend", '<p className="textcolor">'+this.inputElement.value+' has added successfully</p>');
this.inputElement.value='';
setTimeout( () => {
this.divRef.querySelector(':last-child').remove();
}, 3000);
}
}else{
this.inputElement.value='';
}
}
deleteItem(key) {
const result = window.confirm('Are you sure to delete this item');
if (result) {
var filteredItems = this.state.items.filter(function (item) {
return (item.key !== key);
});
this.setState({
items: filteredItems
});
}
}
editItem(key){
this.state.items.map(item =>{
if (item.key==key) {
this.inputElement.value=item.text;
}
})
this.setState({editKey: key});
}
saveEditedText(){
let value = this.inputElement.value;
this.setState(prevState => ({
items: prevState.items.map(el => {
if(el.key == prevState.editKey)
return Object.assign({}, el, {text: value});
return el;
}),
editKey: ''
}));
let maliciousStr = this.listOfKeyWords.find(tag => {
return this.inputElement.value.toLowerCase().indexOf(tag) !== -1;
});
if (!maliciousStr) {
this.divRef.insertAdjacentHTML("beforeend", '<p className="textcolor">'+this.inputElement.value+' has updated successfully</p>');
setTimeout( () => {
this.divRef.querySelector(':last-child').remove();
}, 3000);
this.inputElement.value='';
}else{
this.inputElement.value='';
}
}
render() {
return (
<div className="todoListMain">
<div className="header" id="parentDiv">
<div className="pageHeading" dangerouslySetInnerHTML={{ __html: "Todo Demo Application" }}></div>
<div className="wrapper">
<div ref={divEl => {
this.divRef = divEl;
}}></div>
<form onSubmit={this.addItem}>
<input ref={(a)=>this.inputElement=a} placeholder="enter task">
</input>
<button type="submit">{this.state.editKey? "Update": "Add"}</button>
</form>
<TodoItems entries={this.state.items} delete={this.deleteItem} edit={this.editItem}/>
</div>
</div>
</div>
);
}
}
export default TodoList;
Here I am adding data and after submitting the message is displaying on the top. Here I have one validation if user input has value like <script>Hii</script> the the message will not display or the value can not be added but in my coding its not happening like this. I need if <script>Hii</script> is there those will be filtered out.

reactjs components communicating

I have created two separate components and a parent component. I am trying to see how I can connect them so that I can have the dropdown for the children vanish when their checkbox is unchecked. I think I may have created this so the 2 components can't communicate, but I wanted to see if there was a way to get them to. Been trying different ways, but cannot seem to figure it out.
This is the parent component. It builds sections from some data and renders a checkbox treeview with the first (parent) checkbox having a dropdown. When the third option is selected in this dropdown, it renders in a dropdown for each child checkbox. I am trying to see if I can have the child dropdowns vanish when the checkbox is unchecked, but I can't seem to get the 2 components to communicate.
export default class CheckboxGroup extends PureComponent {
static propTypes = {
data: PropTypes.any.isRequired,
onChange: PropTypes.func.isRequired,
counter: PropTypes.number,
};
mapParents = (counter, child) => (
<li key={child.get('name')} className='field'>
<SegmentHeader style={segmentStyle} title={child.get('label')} icon={child.get('icon')}>
<div className='fields' style={zeroMargin}>
<div className='four wide field'>
<TreeCheckbox
label={`Grant ${child.get('label')} Permissions`}
counter={counter}
onChange={this.props.onChange}
/>
{child.get('items') && this.buildTree(child.get('items'), counter + child.get('name'))}
</div>
<div className='twelve wide field'>
<GrantDropdown label={child.get('label')} childItems={child.get('items')}/>
</div>
</div>
</SegmentHeader>
</li>
)
mapDataArr = (counter) => (child) => (
(counter === 0 || counter === 1000) ?
this.mapParents(counter, child)
:
<li key={child.get('name')}>
<TreeCheckbox label={child.get('label')} onChange={this.props.onChange}/>
{child.get('items') && this.buildTree(child.get('items'), counter + child.get('name'))}
</li>
)
buildTree = (dataArr, counter) => (
<ul key={counter} style={listStyle}>
{dataArr.map(this.mapDataArr(counter))}
</ul>
)
render() {
return (
<div className='tree-view'>
{this.buildTree(this.props.data, this.props.counter)}
</div>
);
}
}
import React, { PureComponent } from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
const pointer = { cursor: 'pointer' };
class TreeCheckbox extends PureComponent {
static propTypes = {
onChange: PropTypes.func,
label: PropTypes.string,
currentPerson: PropTypes.any,
};
componentDidMount() {
if (this.props.currentPerson.get('permissions').includes(this.props.label)) {
this.checkInput.checked = true;
this.changeInput(this.checkInput);
}
}
getLiParents = (el, parentSelector) => {
if (!parentSelector) parentSelector = document; // eslint-disable-line
const parents = [];
let parent = el.parentNode;
let o;
while (parent !== parentSelector) {
o = parent;
if (parent.tagName === 'LI') parents.push(o);
parent = o.parentNode;
}
return parents;
}
traverseDOMUpwards = (startingEl, steps) => {
let elem = startingEl;
for (let i = 0; i < steps; i++) {
elem = elem.parentNode;
}
return elem;
}
markIt = (nodeElem, checkIt, indeter) => {
const node = nodeElem;
const up = this.traverseDOMUpwards(node, 1);
node.checked = checkIt;
node.indeterminate = indeter;
this.props.onChange(up.children[1].innerText, checkIt);
}
changeInput = (event) => {
const e = event === this.checkInput ? event : event.target;
const selector = 'input[type="checkbox"]';
const querySelector = (el) => el.querySelectorAll(selector);
const container = this.traverseDOMUpwards(e, 2);
const markAllChildren = querySelector(container.parentNode);
const checked = e.tagName === 'LABEL' ? !markAllChildren[0].checked : e.checked;
const siblingsCheck = (element) => {
let onesNotRight = false;
const sibling = [].slice.call(element.parentNode.children);
sibling.filter(child => child !== element).forEach(elem => {
if (querySelector(elem)[0].checked !== querySelector(element)[0].checked) {
onesNotRight = true;
}
});
return !onesNotRight;
};
const checkRelatives = (ele) => {
let el = ele;
if (el.tagName === 'DIV') el = el.parentNode;
if (el.tagName !== 'LI') return;
const parentContainer = this.traverseDOMUpwards(el, 2);
if (siblingsCheck(el) && checked) {
this.markIt(querySelector(parentContainer)[0], true, false);
checkRelatives(parentContainer);
} else if (siblingsCheck(el) && !checked) {
const parent = this.traverseDOMUpwards(el, 2);
const indeter = parent.querySelectorAll(`${selector}:checked`).length > 0;
this.markIt(querySelector(parent)[0], false, indeter);
checkRelatives(parent);
} else {
for (const child of this.getLiParents(el)) {
this.markIt(querySelector(child)[0], false, true);
}
}
};
for (const children of markAllChildren) {
this.markIt(children, checked, false);
}
checkRelatives(container);
};
getRef = (input) => { this.checkInput = input; }
render() {
const { label } = this.props;
return (
<div className='permission-item'>
<div className='ui checkbox'>
<input type='checkbox' onChange={this.changeInput} ref={this.getRef}/>
<label onClick={this.changeInput} style={pointer}>
{label}
</label>
</div>
</div>
);
}
}
const mapStatetoProps = (state) => ({
currentPerson: state.get('currentPerson'),
});
export default connect(mapStatetoProps)(TreeCheckbox);
class GrantDropdown extends AbstractSettingsComponent {
static propTypes = {
label: PropTypes.string,
currentPerson: PropTypes.any,
counter: PropTypes.number,
permissionOptions: PropTypes.any,
};
state = {
items: new List(),
}
componentDidMount() {
if (this.props.childItems) {
this.getAllChildLabels(this.props.childItems);
}
}
getAllChildLabels = (childItems) => {
let list = new List();
for (const item of childItems) {
list = list.push(item.get('label'));
if (item.get('items')) {
for (const childItem of item.get('items')) {
list = list.push(childItem.get('label'));
}
}
}
this.setState({ items: list });
}
handlePermissionChange = (label) => (e, { value }) => {
this.updatePerson(['locationsPermissionsMap', label], value);
}
mapItems = (val, i) => { // eslint-disable-line
const locationVal = this.props.currentPerson.getIn(['locationsPermissionsMap', val]);
return (
<div className={locationVal === 2 ? 'two fields' : 'field'} style={zeroMarginBottom} key={i}>
<OptionSelector
options={this.firstThreePermissionOpt()}
defaultValue={locationVal || 0}
onChange={this.handlePermissionChange(val)}
/>
{locationVal === 2 &&
<div className='field' style={zeroMarginBottom}>
<LocationMultiSelect name={val} {...this.props}/>
</div>
}
</div>
);
}
render() {
const { label, currentPerson } = this.props;
if (!currentPerson.get('permissions').includes(label)) {
return null;
}
const locationLabel = currentPerson.getIn(['locationsPermissionsMap', label]);
return (
<div className={ locationLabel === 2 ? 'two fields' : 'field'} style={zeroMarginBottom}>
<div className='field'>
<OptionSelector
options={this.getPermissionOptions()}
defaultValue={currentPerson.getIn(['locationsPermissionsMap', label]) || 0}
onChange={this.handlePermissionChange(label)}
/>
{locationLabel === 3 && this.state.items.map(this.mapItems)}
</div>
{locationLabel === 2 &&
<div className='field'>
<LocationMultiSelect name={label} {...this.props}/>
</div>
}
</div>
);
}
}
const mapStatetoProps = (state) => ({
currentPerson: state.get('currentPerson'),
locations: state.get('locations'),
});
export default connect(mapStatetoProps)(GrantDropdown);
What you can do is set couple of props to send to child component to re-render them.
Example
export default class CheckBoxComponent extends React.Component {
changeInput() {
this.props.onCheckedChanged();
}
render() {
return(
<div className='permission-item'>
<div className='ui checkbox'>
<input type='checkbox' onChange={this.changeInput} ref={this.getRef}/>
<label onClick={this.changeInput.bind(this)} style={pointer}>
{label}
</label>
</div>
</div>
)
}
}
export default class DropDownComponent extends React.Component {
renderSelect() {
// here render your select and options
}
render() {
return(
<div>
{this.props.checkboxChecked === false ? this.renderSelect : null}
</div>
)
}
}
export default class App extends React.Component {
constructor(props) {
super(props);
this.state = {
checkboxChecked: false
};
}
onCheckedChanged() {
this.setState({ checkboxChecked: !this.state.checkboxChecked });
}
render() {
return(
<div>
<CheckBoxComponent onCheckedChanged={this.onCheckedChanged.bind(this)} />
<DropDownComponent checkboxChecked={this.state.checkboxChecked} />
</div>
)
}
}
You can set the <input/> name attribute into a corresponding property in your state so the handler can get the name of the list / input via the event parameter and set the state respectively.
Then you can conditionally render the Dropdown according to the state.
Here is a small example of such behavior:
const lists = [
[
{ value: "0", text: "im 0" },
{ value: "1", text: "im 1" },
{ value: "2", text: "im 2" }
],
[
{ value: "a", text: "im a" },
{ value: "b", text: "im b" },
{ value: "c", text: "im c" }
]
];
const DropDown = ({ options }) => {
return (
<select>
{options.map(opt => <option value={opt.value}>{opt.text}</option>)}
</select>
);
};
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
showList0: false,
showList1: true
};
this.toggleCheck = this.toggleCheck.bind(this);
}
toggleCheck(e) {
const listName = e.target.name;
this.setState({ [listName]: !this.state[listName] });
}
render() {
return (
<div>
{lists.map((o, i) => {
const listName = `showList${i}`;
const shouldShow = this.state[listName];
return (
<div>
<input
type="checkbox"
name={listName}
checked={shouldShow}
onChange={this.toggleCheck}
/>
{shouldShow && <DropDown options={o} />}
</div>
);
})}
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>

Categories

Resources