Determine clicked item and update aria-checked value in React - reactjs

render(){
return (
<div>
this.data.map(item=> {
<div aria-checked="true/false">{item}<div>
})
</div>
)
}
For the above code, I want to write an onClick handler that changes the value of aria-checked to true, depending on the item selected/clicked on. If one item is selected, it's aria-checked will be true and the rest false.
I know I need a checked component state with a boolean type but I'm not sure how to do the handler logic.

you can do by setAttribute, here:
constructor() {
super();
this.data = ["hello", "world"];
}
handleClick = (e) => {
const currentAriaChecked = (e.currentTarget.getAttribute("aria-checked") === 'true');
e.currentTarget.setAttribute("aria-checked", !currentAriaChecked);
};
render() {
return (
<div>
{
this.data
.map(item => (<div aria-checked="true" onClick={this.handleClick}>{item}</div>))
}
</div>
);
}
UPDATE
using typescript and react way
render() {
return (
<div>
{
this.data
.map(item => (<Check>{item}</Check>))
}
</div>
);
}
your component check
state = {
isChecked: false
}
handleClick = (e) => {
this.setState((prevState,props) => {
return {isChecked: !prevState.isChecked }
})
};
render() {
return (
<div aria-checked={this.state.isChecked} onClick={this.handleClick}>
{this.props.children} {this.state.isChecked.toString()}
</div>
);
}
see playground.

Related

function component vs function - the sense of using function components

My problem is I do not really understand if using function components instead function is good idea in below example:
first program without function components
class App extends React.Component {
state = {
check: false,
isFormSubmitted: false
}
handleChangeChecked = () => {
this.setState({
check: !this.state.check,
isFormSubmitted: false
})
return (true)
}
displayMsg = () => {
if (this.state.isFormSubmitted == true) {
if (this.state.check == true)
return (<p>You are allowed to watch this film!</p>)
else return (<p>You are not allowed to watch this film.</p>)
} else return (null)
}
handleFormSubmit = (e) => {
e.preventDefault()
this.setState({
isFormSubmitted: true
})
}
render() {
return (
<React.Fragment>
<h1>Film</h1>
<form onSubmit={this.handleFormSubmit}>
<input type="checkbox" onChange={this.handleChangeChecked} checked={this.state.check} />
<label>I have got 16 years old</label>
<button>Buy ticket</button>
</form>
{this.displayMsg()}
</React.Fragment>
)
}
}
ReactDOM.render(< App />, document.getElementById('root'));
second program with function components:
const PositiveMessage = () => <p>Mozesz obejrzeć film, zapraszam</p>;
const NegativeMessage = () => <p>Nie możesz obejrzeć tego filmu !</p>;
class TicketShop extends React.Component {
state = {
isConfirmed: false,
isFormSubmitted: false
}
handleCheckboxChange = () => {
this.setState({
isConfirmed: !this.state.isConfirmed,
isFormSubmitted: false
})
}
displayMessage = () => {
if (this.state.isFormSubmitted) {
if (this.state.isConfirmed) { return <PositiveMessage /> }
else { return <NegativeMessage /> }
} else { return null }
}
handleFormSubmit = (e) => {
e.preventDefault()
if (!this.state.isFormSubmitted) {
this.setState({
isFormSubmitted: !this.state.isFormSubmitted
})
}
}
render() {
return (
<>
<h1>Kup bilet na horror roku !</h1>
<form onSubmit={this.handleFormSubmit}>
<input type="checkbox" id="age" onChange={this.handleCheckboxChange} checked={this.state.isConfirmed} />
<label htmlFor="age">Mam conajmniej 16 lat</label>
<br />
<button type="submit">Kup bilet</button>
</form>
{this.displayMessage()}
</>
)
}
}
ReactDOM.render(<TicketShop />, document.getElementById('root'))
i made two programs with and without function components and i dont see the difference of working.
In user point of view both programs works without any difference.

delete three level component(a component have an array of component, each have an array of compoent)

I would appreciate it greatly if you could let me know how to deal with this problem.
I hava a page component which has an array of company component, and each company has an array of contract.
If I delete any company, every company component will re-render, so I cant put array of contract under each company state, so I put it under page component state.
The question is If I delete one company, how can I correctly re-render all contracts under each component.
Thank you for reading my problem, and sorry for my poor English:(
Error Message is "TypeError: Cannot read property 'contractList' of undefined"
My page code is...
class IRPage extends Component {
// // initialize our state
state = {
companyList: [],
};
addCompanyArr = (newCompany) => {
this.setState(
state => {
const list = state.companyList.push(newCompany);
return {
list,
};
}
)
};
addContractArr = (index, newContract) => {
this.setState(
state => {
const list = state.companyList[index].contractList.push(newContract);
return {
list,
};
}
);
}
setCompanyArr = () => {
this.setState(
state => {
const list = state.companyList;
return {
list,
};
}
)
};
render() {
return (
<div className="container m-5">
<IRContent companyList={this.state.companyList} setCompanyArr={this.setCompanyArr} addCompanyArr={this.addCompanyArr} addContractArr={this.addContractArr}></IRContent>
</div>
)
}
}
export default IRPage;
My content code is ...
class IRContent extends React.Component {
constructor(props) {
super(props);
}
addCompany = () => {
const companyNode = <IRCompany companyList={this.props.companyList} setCompanyArr={this.props.setCompanyArr} index={this.props.companyList.length} addContractArr={this.props.addContractArr}/>;
const newCompany = {
node: companyNode,
contractList: [],
};
this.props.addCompanyArr(newCompany);
}
render() {
return(
<div className="container col-sm-12 justify-content-center">
<h1 align="center">data</h1>
<hr/>
{
this.props.companyList.map((element, index) => {
return <div key={"myCompanyKey_"+index+"_"+this.props.companyList.length} id={index}>{element.node}</div>;
})
}
<button color="primary" onClick = {this.addCompany}>
add new company
</button>
</div>
);
}
}
export default IRContent;
My company code is...
class IRCompany extends React.Component {
constructor(props) {
super(props);
}
deleteCompany = event => {
event.preventDefault();
var targetID = event.target.parentElement.parentElement.parentElement.parentElement.parentElement.getAttribute("id")
this.props.companyList.splice(targetID, 1);
this.props.setCompanyArr();
};
addContract = event => {
event.preventDefault();
var newContract = <IRContract/>;
var targetID = event.target.parentElement.parentElement.parentElement.parentElement.parentElement.parentElement.parentElement.parentElement.getAttribute("id");
this.props.addContractArr(targetID, newContract);
this.forceUpdate();
};
render() {
return(
<div>
{
this.props.companyList[this.props.index].contractList.map((element, index) => {
return <React.Fragment key={"myContractKey" + index + "_" +this.props.companyList[this.props.index].contractList.length}>{element}</React.Fragment>;
})
}
<button color="primary" onClick = {this.addContract}>主約</button>
</div>
);
}
}
export default IRCompany;
I can successively add company and contract, but there are some problem on deleing.
Thank you for reading my problem, and sorry for my poor English:(

React function - is not defined no-undef

I get the following error when trying to compile my app 'handleProgress' is not defined no-undef.
I'm having trouble tracking down why handleProgress is not defined.
Here is the main react component
class App extends Component {
constructor(props) {
super(props);
this.state = {
progressValue: 0,
};
this.handleProgress = this.handleProgress.bind(this);
}
render() {
const { questions } = this.props;
const { progressValue } = this.state;
const groupByList = groupBy(questions.questions, 'type');
const objectToArray = Object.entries(groupByList);
handleProgress = () => {
console.log('hello');
};
return (
<>
<Progress value={progressValue} />
<div>
<ul>
{questionListItem && questionListItem.length > 0 ?
(
<Wizard
onChange={this.handleProgress}
initialValues={{ employed: true }}
onSubmit={() => {
window.alert('Hello');
}}
>
{questionListItem}
</Wizard>
) : null
}
</ul>
</div>
</>
);
}
}
Your render method is wrong it should not contain the handlePress inside:
You are calling handlePress on this so you should keep it in the class.
class App extends Component {
constructor(props) {
super(props);
this.state = {
progressValue: 0,
};
this.handleProgress = this.handleProgress.bind(this);
}
handleProgress = () => {
console.log('hello');
};
render() {
const { questions } = this.props;
const { progressValue } = this.state;
const groupByList = groupBy(questions.questions, 'type');
const objectToArray = Object.entries(groupByList);
return (
<>
<Progress value={progressValue} />
<div>
<ul>
{questionListItem && questionListItem.length > 0 ?
(
<Wizard
onChange={this.handleProgress}
initialValues={{ employed: true }}
onSubmit={() => {
window.alert('Hello');
}}
>
{questionListItem}
</Wizard>
) : null
}
</ul>
</div>
</>
);
}
}
If you are using handleProgress inside render you have to define it follows.
const handleProgress = () => {
console.log('hello');
};
if it is outside render and inside component then use as follows:
handleProgress = () => {
console.log('hello');
};
If you are using arrow function no need to bind the function in constructor it will automatically bind this scope.
handleProgress should not be in the render function, Please keep functions in you component itself, also if you are using ES6 arrow function syntax, you no need to bind it on your constructor.
Please refer the below code block.
class App extends Component {
constructor(props) {
super(props);
this.state = {
progressValue: 0,
};
// no need to use bind in the constructor while using ES6 arrow function.
// this.handleProgress = this.handleProgress.bind(this);
}
// move ES6 arrow function here.
handleProgress = () => {
console.log('hello');
};
render() {
const { questions } = this.props;
const { progressValue } = this.state;
const groupByList = groupBy(questions.questions, 'type');
const objectToArray = Object.entries(groupByList);
return (
<>
<Progress value={progressValue} />
<div>
<ul>
{questionListItem && questionListItem.length > 0 ?
(
<Wizard
onChange={this.handleProgress}
initialValues={{ employed: true }}
onSubmit={() => {
window.alert('Hello');
}}
>
{questionListItem}
</Wizard>
) : null
}
</ul>
</div>
</>
);
}
}
Try this one, I have check it on react version 16.8.6
We don't need to bind in new version using arrow head functions. Here is the full implementation of binding argument method and non argument method.
import React, { Component } from "react";
class Counter extends Component {
state = {
count: 0
};
constructor() {
super();
}
render() {
return (
<div>
<button onClick={this.updateCounter}>NoArgCounter</button>
<button onClick={() => this.updateCounterByArg(this.state.count)}>ArgCounter</button>
<span>{this.state.count}</span>
</div>
);
}
updateCounter = () => {
let { count } = this.state;
this.setState({ count: ++count });
};
updateCounterByArg = counter => {
this.setState({ count: ++counter });
};
}
export default Counter;

Showing two different components based on return value in react js

I have search function where on entering text it returns the object from an array(json data) and based on the condition (whether it as an object or not) I need to show two different components ie. the list with matched fields and "No matched results found" component.
class Search extends React.Component {
constructor(props) {
super(props);
this.state = {
searchTextData: '',
isSearchText: false,
isSearchOpen: false,
placeholderText:'Search Content',
filteredMockData: [],
dataArray: []
};
}
handleSearchChange = (event, newVal) => {
this.setState({ searchTextData: newVal })
if (newVal == '') {
this.setState({ clearsearch: true });
this.setState({
filteredMockData: []
});
this.props.onDisplayCloseIcon(true);
} else {
this.props.onDisplayCloseIcon(false);
searchData.searchResults.forEach((item, index, array) => {
this.state.dataArray.push(item);
});
this.setState({ filteredMockData: this.state.dataArray });
}
}
clearInput = () => {
this.setState({ searchTextData: '' })
}
isSearchText = () => {
this.setState({ isSearchText: !this.state.isSearchText });
}
onSearchClick = () => {
this.setState({ isSearchOpen: !this.state.isSearchOpen });
this.setState({ searchTextData: '' });
this.props.onDisplayCloseIcon(true);
}
renderSearchData = () => {
const SearchDatasRender = this.state.dataArray.map((key) => {
const SearchDataRender = key.matchedFields.pagetitle;
return (<ResultComponent results={ SearchDataRender } /> );
})
return SearchDatasRender;
}
renderUndefined = () => {
return ( <div className = "search_no_results" >
<p> No Recent Searches found. </p>
<p> You can search by word or phrase, glossary term, chapter or section.</p>
</div>
);
}
render() {
return ( <span>
<SearchIcon searchClick = { this.onSearchClick } />
{this.state.isSearchOpen &&
<div className = 'SearchinputBar' >
<input
placeholder={this.state.placeholderText}
className= 'SearchInputContent'
value = { this.state.searchTextData}
onChange = { this.handleSearchChange }
/>
</div>
}
{this.state.searchTextData !== '' && this.state.isSearchOpen &&
<span className='clearText'>
<ClearIcon className='clearIcon' clearClick = { this.clearInput }/>
</span>
}
{this.state.searchTextData !== '' && this.state.isSearchOpen &&
<div className="SearchContainerWrapper">
<div className = "arrow-up"> </div>
<div className = 'search_result_Container' >
<div className = "search_results_title" > <span> Chapters </span><hr></hr> </div>
<div className="search_show_text" >
<ul className ="SearchScrollbar">
{this.state.filteredMockData.length ? this.renderSearchData() : this.renderUndefined() }
</ul>
</div>
</div>
</div>}
</span>
);
}
}
Search.propTypes = {
intl: intlShape.isRequired,
onSearchClick: PropTypes.func,
isSearchBarOpen: PropTypes.func,
clearInput: PropTypes.func,
isSearchText: PropTypes.func
};
export default injectIntl(Search);
Search is my parent component and based on the matched values I need to show a resultComponent like
class ResultComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
};
}
render(){
console.log(this.props.renderSearchData(),'Helloooo')
return(<p>{this.props.renderSearchData()}</p>)
}
}
ResultComponent.propTypes = {
results: PropTypes.string.isRequired
};
I'm getting an error "renderSearchData is not an function".I'm new to react and Hope someone can help.
The only prop passed to ResultComponent component is results
So in ResultComponent Component Replace
this.props.renderSearchData()
With
this.props.results

Having trouble getting this function to bind correctly in react

My handleTeamChange function is erroring and coming back as undefined when the renderTeamMethod runs. I tried passing the variable team into on like "this.handleTeamChange.bind(this, team)" as well but nothing. I've tried a ton of different ways to call teh handleTeamChange method but so far nothing but undefined. Any thoughts?
import React, { Component } from 'react';
import UserDropdown from './user-dropdown';
import { getTeams } from 'api/index.js';
let teams = [];
let selectedTeamID = null;
let selectedTeamName = 'all_teams';
let teamId = '';
export default class TopNav extends Component {
constructor(props, context) {
super(props, context);
// this.handleTeamChange = this.handleTeamChange.bind(this);
this.state = {
teams: [],
team: {},
selectedTeamID: null,
selectedTeamName: 'All Teams',
teamSelection: false
};
}
handleClick() {
this.setState({
teamSelection: true
});
}
componentWillMount() {
getTeams().then((response) => {
teams = response.data;
this.setState({teams: teams});
});
}
renderTeams() {
return teams.map(function(team) {
if (team.active === true) {
return (
<div
onClick={ () => { this.handleTeamChange(team) } }
className="team-filter-team"
key={team.id}
value={team.id} >{team.TeamName}
</div>
);
}
});
}
handleTeamChange(team) {
console.log(team);
}
render () {
return (
<nav className="nav-wrapper">
<img className="logo-medium nav-logo" src={"https://s3-us-west-2.amazonaws.com/mvtrak/MVTRAKbrandmark.png"} />
<div onClick={ this.handleClick.bind(this) } className="team-selected"> { this.state.selectedTeamName } </div>
<div className="team-filter-container">
{this.renderTeams()}
</div>
<UserDropdown />
</nav>
);
}
}
the function body where you're mapping teams is not bound to the component's scope, therefore this is undefined.
change teams.map(function (team) { ... }) to e.g. a fat arrow teams.map((team) => ... ):
return teams.filter(team => team.active).map((team) => (
<div
onClick={ () => { this.handleTeamChange(team) } }
className="team-filter-team"
key={team.id}
value={team.id}
>
{team.TeamName}
</div>
))

Resources