I am having the following code. There's some issue I'm facing right now with this thing in my project. I want to use the forEach() loop there inside getElements() instead of map() and also I want to simply show it default checked whenever after checking on a checkbox, going next and again returning back there.
Any help with this issue ??
here's the => DEMO
import React, { Component } from 'react';
import { render } from 'react-dom';
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider';
import Checkbox from 'material-ui/Checkbox';
class App extends Component {
itemsPerPage = 4
constructor(props) {
super(props);
var ids = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
this.state = {
ids: ids,
idsChecked: ids.map(() => false),
page: 0
}
}
componentDidMount = () => {
}
handlePrevious = () => {
this.setState({ page: this.state.page - 1 });
}
handleNext = () => {
this.setState({ page: this.state.page + 1 });
}
handleCheck = (e) => {
var id = Number(e.currentTarget.id);
var idsChecked = this.state.idsChecked.map((bool, i) => i === id ? !bool : bool);
this.setState({ idsChecked: idsChecked });
}
handleDetails = (e) => {
var id = Number(e.currentTarget.getAttribute("rel"));
console.log("even or odd is clicked! (button #id: " + id + ")");
}
getElements = () => {
var first = this.state.page * this.itemsPerPage;
var trs = this.state.ids.slice(first, first + this.itemsPerPage).map((element, i) => {
let details = <button rel={first + i} onClick={this.handleDetails}> {element % 2 ? "odd" : "even"} </button>;
return (
<tr key={element}>
<td><Checkbox
checked={this.state.idsChecked[first + i]}
id={first + i}
onCheck={this.handleCheck}
/></td>
<td>{element}</td>
<td>{details}</td>
</tr>
);
});
return trs;
}
render() {
var hasPrevious = this.state.page > 0;
var hasNext = this.state.page < Math.floor((this.state.ids.length - 1) / this.itemsPerPage);
var tdStyle = {width: "80px"}
return (
<div>
<div>
<table>
<tbody>
<tr>
<td style={tdStyle}>{hasPrevious && <button onClick={this.handlePrevious} hidden={this.state.hasPrevious}> Previous </button>}</td>
<td style={tdStyle}>{hasNext && <button onClick={this.handleNext} hidden={this.state.isNext}> Next </button>}</td>
</tr>
</tbody>
</table>
</div>
<div>
<table>
<tbody>
{this.getElements()}
</tbody>
</table>
</div>
</div>
);
}
}
render(<MuiThemeProvider><App /></MuiThemeProvider>, document.getElementById('root'));
To replace, map with forEach, push the checkbox elements onto an array, and return that array from your getElements().
Use the defaultChecked props of the <Checkbox> component to set the default value to true.
Full code:
getElements = () => {
var first = this.state.page * this.itemsPerPage;
let checkboxArray = []; // array for storing the elements
this.state.ids.slice(first, first + this.itemsPerPage).forEach((element, i) => {
let details = <button rel={first + i} onClick={this.handleDetails}> {element % 2 ? "odd" : "even"} </button>;
checkboxArray.push(
<tr key={element}>
<td><Checkbox
checked={this.state.idsChecked[first + i]}
id={first + i}
defaultChecked={true/*use the defaultChecked prop*/}
onCheck={this.handleCheck}
/></td>
<td>{element}</td>
<td>{details}</td>
</tr>
);
});
return checkboxArray; // return the array
}
render() {
var hasPrevious = this.state.page > 0;
var hasNext = this.state.page < Math.floor((this.state.ids.length - 1) / this.itemsPerPage);
var tdStyle = {width: "80px"}
return (
<div>
<div>
<table>
<tbody>
<tr>
<td style={tdStyle}>{hasPrevious && <button onClick={this.handlePrevious} hidden={this.state.hasPrevious}> Previous </button>}</td>
<td style={tdStyle}>{hasNext && <button onClick={this.handleNext} hidden={this.state.isNext}> Next </button>}</td>
</tr>
</tbody>
</table>
</div>
<div>
<table>
<tbody>
{this.getElements()}
</tbody>
</table>
</div>
</div>
);
}
}
Related
When a player scores, I want to add +1 to the players total score (totPoints).
Unfortunately, my present code:
const [number, setNumber] = useState('');
const [totPoints, setTotPoints] = useState(0);
const [scorers, setScorers] = useState([]);
const sortedScorers = [...scorers].sort((a, b) => a.number - b.number);
const onePointScoredHandler = () => {
const players = [...scorers];
const pos = players.map((player) => player.number).indexOf(+number);
if (pos !== -1) {
console.log('exist');
players[pos].totPoints = setTotPoints(totPoints + 1);
setScorers(players);
} else {
console.log('new');
const newScorer = {
id: nanoid(4),
number: +number,
totPoints: totPoints + 1,
};
setScorers([...scorers, newScorer]);
setTotPoints(totPoints);
}
setNumber('');
console.log(scorers);
};
return (
<div className="App">
<h4>Individual points</h4>
<br />
<br />
<br />
<input
type="number"
value={number}
onChange={(e) => setNumber(e.target.value)}
/>
<br />
<br />
<button onClick={onePointScoredHandler}>Add 1p</button>
<br />
<br />
<table className="table">
<thead>
<tr>
<th>ID</th>
<th>NUMBER</th>
<th>Total Points</th>
</tr>
</thead>
<tbody>
{sortedScorers
.sort((a, b) => a.number - b.number)
.map((player) => (
<tr key={player.id}>
<td>{player.id}</td>
<td>{player.number}</td>
<td>{player.totPoints}</td>
</tr>
))}
</tbody>
</table>
</div>
);
};
don't works as intended:
When the player scores first time, it's working, i.e totPoints = 1
if that player scores again i get totPoints: undefined
If now a new player scores, the totPoints = 2 and nottotPoints = 1 as it should be
I hope you can rescue me even this time....
Thanks in advance
Regards
Peter
PS: I´ve tried with
players[pos].totPoints = setTotPoints((prevState) => prevState + 1)
with the same disappointing results...
Issue
You are mutating the state object.
players[pos].totPoints = setTotPoints(totPoints + 1); // mutation!!
setScorers(players);
Even though you copied the array with const players = [...scorers]; the elements in the array still reference the elements of the old array.
Solution
Use a functional state update to match a previous scorer to increment their totPoints value. Remember, when updated React state you must shallow copy any state that is being updated, included nested state.
setScorers((scorers) =>
scorers.map((scorer, index) =>
index === pos
? {
...scorer,
totPoints: scorer.totPoints + 1
}
: scorer
)
);
I hope my title is enough to understand my question, ive been post this question several times but I hope this time I get help from you guys.
<table id="blacklistgrid" border="2px">
<tr>
th id="th">Students Name</th>
</tr>
{% for student in teacherStudents %}
<tr class="tr2">
<td id="td">{{ student.Students_Enrollment_Records.Student_Users }}</td>
</tr>
{% endfor %}
</tr>
</table>
<button type="button" value="" class="save" onclick="doTheInsert()" title="Insert New Cell" id="save">+ Insert New Cell</button>
<button type="button" value="" class="save" onclick="undoTheInsert()" title="Undo Recent Action" id="unsave">× Undo Recent Action</button>
<button type="button" value="" class="save" onclick="compute()" title="Undo Recent Action" id="compute">Compute</button>
this is my script for the button Insert Cell
<script>
var counter = 0;
function doTheInsert(){
let header=$("tr#tr"); // same as $.find("tr[id='tr2']")
$('#th').after("<th data-id='headers' id='header'><input type='date'></th>");
let rows=$(".tr2");
rows.append("<td data-id='row' ><input type='number' class='average'/></td>");
counter++;
}
</script>
this is my current script in computation
<script>
function compute(){
var sum = 0;
var rows = document.getElementsByClassName("average");
for(var i = 0; i < counter; i++){
sum += parseInt(rows[i].value);
}
var average = sum / counter;
document.getElementById("demo").innerHTML = average;
let header=$("tr#tr"); // same as $.find("tr[id='tr2']")
$('#thb').before("<th data-id='headers' id='headerss'>Average</th>");
}
</script>
this is the results I get ,
it only compute the average of first students
this is the result I want
when ive tried this query from Mr #Saket Yadav
<script>
function compute(){
var sum = 0;
var rows = document.getElementsByClassName("average");
$(".average").each(function () {
sum += parseInt($(this).val());
});
console.log("Sum:"+sum);
var average = sum / counter;
document.getElementById("demo").innerHTML = average;
let header=$("tr#tr"); // same as $.find("tr[id='tr2']")
$('#thb').before("<th data-id='headers' id='headerss'>Average</th>");
}
</script>
ive got this result
this is what i want in my result
Kindly update your JavaScript compute function as shown below.
<script>
function compute(){
let header=$("tr#tr"); // same as $.find("tr[id='tr2']")
$('th:last-child').after("<th data-id='headers' id='header'>Average</th>");
let rows1=$(".tr2");
rows1.append("<td data-id='row' ><input type='number' class='averages'/></td>");
$('tr').each(function () {
var sum = 0
var i=0;
$(this).find('.average').each(function () {
var textVal = $(this).val();
console.log(textVal);
if (!isNaN(textVal) && textVal.length !== 0) {
sum += parseFloat(textVal);
}
i++;
});
var avg=sum/i;
$('.averages', this).val(avg);
});
}
</script>
I would do something like this (using react instead of jquery)
const App = () => {
const [ students, setStudents ] = React.useState([{
id: 0,
name: 'Jonh',
notes: [
{ date: '2020-01-02', note: 4 },
{ date: '2020-01-03', note: 12 }
]
}]);
const [ days, setDays ] = React.useState([
'2020-01-02',
'2020-01-03'
])
const [ newStudentName, setNewStudentName ] = React.useState('Name')
const getAverage = notes => {
return notes.reduce((sum, { note }) => sum + parseInt(note), 0)/notes.length;
}
const addStudent = () => {
setStudents([
...students, {
id: +new Date(),
name: newStudentName,
notes: days.map(date => ({ date, note: null }))
}
])
}
const setNote = (studentId, noteDate, newNote) => {
const nextStudents = students.map(student => {
if (student.id === studentId) {
return {
...student,
notes: student.notes.map(({ note, date }) => (
date === noteDate ? { note: newNote, date } : { note, date }
))
}
}
return student;
})
setStudents(nextStudents)
}
return (
<div>
<table>
<tr>
<th>Name</th>
{days.map(day => <th>{day}</th>)}
<th>Average</th>
</tr>
{students.map(({ id: studentId, name, notes })=> (
<tr>
<td>
{name}
</td>
{notes.map(({ date, note }) => <td><input type="number" onChange={({ target: { value }}) => setNote(studentId, date, value)} value={note} /></td>)}
<td>{getAverage(notes)}</td>
</tr>
))}
</table>
<input onChange={({target: { value }}) => setNewStudentName(value)} value={newStudentName} />
<button onClick={() => addStudent()}>Add student</button>
</div>
)
};
ReactDOM.render(<App />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.12.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.11.0/umd/react-dom.production.min.js"></script>
<div id="root"></div>
I want to take the numbers from 1 to 12 & want to show them by 4 items in the component like - first 4 numbers with the checkboxes at first, after clicking on next button next 4 numbers with the checkboxes should be showing up with and the previous button comes up to go back ... like this.. & also the even - odd buttons should be showing up beside them & suppose I'm checking on one checkbox in the component when I'm clicking on next and again coming back there, that checkbox should be showing selected or checked.
There have some problem in the code that's why what I'm wanting is not happening. Any help ?
Click here to see the - DEMO
import React, { Component } from 'react';
import { render } from 'react-dom';
import Hello from './Hello';
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider';
import Checkbox from 'material-ui/Checkbox';
class App extends Component {
constructor() {
super();
this.state = {
ids:[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],
getids:[],
idstaken:[],
isPrevious: true,
isNext: false,
counter:0
}
this.getElements = this.getElements.bind(this);
this.handleCheck = this.handleCheck.bind(this);
this.handleDetails = this.handleDetails.bind(this);
this.handlePrevious = this.handlePrevious.bind(this);
this.handleNext = this.handleNext.bind(this);
}
componentDidMount() {
let arr = [];
for(var i=0; i<4; i++) {
arr.push(this.state.ids[i]);
}
this.setState({getids: arr});
}
handlePrevious() {
let arr = [];
if(this.state.counter == 8) {
this.setState({isPrevious: true, isNext: false});
}
for( var i = (this.state.counter - 8); i < (this.state.counter - 4); i++){
arr.push(this.state.ids[i]);
}
this.setState({counter: arr.length, getids: arr});
}
handleNext() {
let arr = [];
if(this.state.counter == 8) {
this.setState({isPrevious: false, isNext: true});
}
for(var i = this.state.counter; i < (this.state.counter + 4); i++){
arr.push(this.state.ids[i]);
}
this.setState({counter: arr.length, getids: arr});
}
handleCheck(e) {
this.state.idstaken.push(e.currentTarget.id);
console.log(e.currentTarget.id);
}
handleDetails() {
console.log("even or odd is clicked!");
}
getElements() {
let details;
let array = [];
let temp = [];
this.state.getids.forEach(function(element) {
if(element % 2 == 0) {
details = <button onClick={this.handleDetails}> even </button>;
}
else {
details = <button onClick={this.handleDetails}> odd </button>;
}
temp.push(
<tr>
<td><Checkbox
id={element}
onCheck={this.handleCheck}
/></td>
<td>{element}</td>
<td>{details}</td>
</tr>
);
}, this)
return temp;
}
render() {
return(
<MuiThemeProvider>
<div>
<div>
<table>
<tr>
<td><button onClick = {this.handlePrevious} hidden={this.state.isPrevious}> Previous </button></td>
<td><button onClick = {this.handleNext} hidden={this.state.isNext}> Next </button></td>
</tr>
</table>
</div>
<div>
<table>
{this.getElements()}
</table>
</div>
</div>
</MuiThemeProvider>
);
}
}
render(<App />, document.getElementById('root'));
var Admin = React.createClass({
saveUpload: function(id) {
alert(id);
},
getInitialState() {
return {
uploads: []
};
},
componentDidMount() {
var self = this;
$.ajax({
url: 'http://localhost:8080/admin/uploads',
success: function(data) {
self.setState({
uploads: data
})
}
});
},
render: function() {
var obj = this.state.uploads.map(function(product) {
return (
<Uploads product = {product}
saveHandle = {this.saveUpload}
/>
)
});
return (
< div >
<div className = "container" >
<br / >
<h1 className = "text-center" > Welcome Admin < /h1>
<br / > < br / >
<hr / >
</div>
<h3 className = "text-center" > Company Upload Details < /h3>
<div className = "container" >
<table className = "table" >
<thead className = "thead-light" >
<tr >
<th > Id < /th> <th > CompanyName < /th>
<th > Date & Time < /th> <
th > FileName(csv) < /th> <
th > Size(KB) < /th> <
th > Status < /th> <
/tr> <
/thead> {
obj
} <
/table>
</div> </div>
)
}
});
here is the uploads component
var Uploads = React.createClass({
show() {
this.props.saveHandle(this.props.product.id);
},
render() {
return (
<tr>
<td> {this.props.product.id} </td>
<td> {this.props.product.company.companyName} </td>
<td> {(new Date(this.props.product.date)).toString()} </td>
<td> {this.props.product.fileName} </td>
<td> {this.props.product.filesize} </td>
<td> {this.props.product.status} </td>
<td>
<button className = "button" onClick = {this.show}> Save </button>
</td>
</tr>
)
}
});
Here is my code i am passing id from Uploads component to admin component when save button is clicked but it gives me an error that saveUpload is not defined.
I am confused my it is giving me that error i have a function saveUpload in Admin Component. what is wrong in this code
The bug is here:
var obj = this.state.uploads.map(function(product) {
return (
<Uploads product = {product}
saveHandle = {this.saveUpload}
/>
)
});
Inside the map(), this is no longer the instance of your Admin component, it is window. If you bind it like so:
var obj = this.state.uploads.map(function(product) {
return (
<Uploads product = {product}
saveHandle = {this.saveUpload}
/>
)
}.bind(this));
Then this will point to the Admin instance and you should get the function you're expecting. If you have ES6 available, you could also write it like this:
var obj = this.state.uploads.map(product =>
<Uploads product = {product}
saveHandle = {this.saveUpload}
/>);
Using the "fat arrow" => lambda expression, this is automatically bound to the enclosing scope inside, saving you some effort.
I'm trying to render a select dropdown menu with years.
I'm using a simple loop to generates all the years for the dropdown menu, see dateYear().
If I place {this.dateYear()} outside of {this.state.careerHistoryPositions.map((careerHistoryPosition) it renders correctly however when I place it inside {this.state.careerHistoryPositions.map((careerHistoryPosition) it renders the select element however the years don't populate.
I'm not getting any errors in console either.
export default class CareerHistoryFormPage extends Component {
constructor(props) {
super(props);
const profileCandidateCollection = props.profileCandidate;
const careerHistoryPositions = profileCandidateCollection && profileCandidateCollection.careerHistoryPositions;
this.state = {
careerHistoryPositions: [{company: '', startDateYear: ''}],
};
}
dateYear() {
var yearDate = '';
for (var i = new Date().getFullYear(); i >= 1975; i--) {
yearDate += '<option value="' + i + '">' + i + '</option>';
}
$('select').html('<option>Year</option>' + yearDate);
}
}
render() {
return (
<form onSubmit={this.handleFormSubmit}>
{this.state.careerHistoryPositions.map((careerHistoryPosition) => (
<div key={careerHistoryPosition.uniqueId}>
<input
type="text"
value={careerHistoryPosition.company}
onChange={this.handleCompanyNameChange(careerHistoryPosition.uniqueId)}
/>
<select value={CareerHistoryFormPage.startDateYear} >
{this.dateYear()}
</select>
</div>
</form>
);
}
}
I don't think this is the most elegant solution, however, it's how I got it working. The problem was jquery. Thanks to #nem035 for pointing that out.
export default class CareerHistoryFormPage extends Component {
constructor(props) {
super(props);
const profileCandidateCollection = props.profileCandidate;
const careerHistoryPositions = profileCandidateCollection && profileCandidateCollection.careerHistoryPositions;
this.state = {
careerHistoryPositions: [{company: '', startDateYear: ''}],
};
}
getStartDateMonthSelect(careerHistoryPosition) {
const monthRange = [];
for (let i = 0; i <= 11; i++) {
monthRange.push(i);
}
return (
<select value={careerHistoryPosition.startDateMonth} onChange={this.handleStartDateMonthChange(careerHistoryPosition.uniqueId)}>
<option>Month</option>
{monthRange.map(month => (
<option key={month} value={month}>{moment().month(month).format('MMMM')}</option>
))}
</select>
);
}
}
render() {
return (
<form onSubmit={this.handleFormSubmit}>
{this.state.careerHistoryPositions.map((careerHistoryPosition) => (
<div key={careerHistoryPosition.uniqueId}>
<input
type="text"
value={careerHistoryPosition.company}
onChange={this.handleCompanyNameChange(careerHistoryPosition.uniqueId)}
/>
{this.getStartDateMonthSelect(careerHistoryPosition)}
</div>
</form>
);
}
}