Change color of selected page number (pagination) - javascript

I have created a simple React component with a table displaying 10 rows of data per page. The implementation of the pagination works as intended, but I want to be able to highlight the selected page.
In my constructor I have an initial state "active: null", which I then modify in a handleClick function.
constructor(props) {
super(props);
this.state = {
currentPage: 1,
eventsPerPage: 10,
active: null,
};
this.handleClick = this.handleClick.bind(this);
}
handleClick(index) {
this.setState({ currentPage: Number(index.target.id) });
if (this.state.active === index) {
this.setState({ active: null });
} else {
this.setState({ active: index });
}
}
And a function for setting the font-weight to bold.
myStyle(index) {
if (this.state.active === index) {
return 'bold';
}
return '';
}
Here is what I render.
const renderPageNumbers = pageNumbers.map((number, index) => (
<p
style={{ fontWeight: this.myStyle(index) }}
key={number}
id={number}
onClick={index => this.handleClick(index)}
>
{number}
</p>
));
return (
<div id="page-numbers">
{renderPageNumbers}
</div>
);
FYI: It's not the complete code.
I am not quite sure where I go wrong, any help is appreciated :)

pageNumbers.map((number, index) => index is zero based and am sure number starts from 1 so when index === 0 and number === 1, you would have this.myStyle(0) but
this.handleClick(0) will not work because you first #id === 1 not 0
why not just use number for your functions and remove index to safe confusion

You need to bind the context of the class to myStyle function in order to use this inside it.
So, in your constructor you should add it like this:
(see the last line)
constructor(props) {
super(props);
this.state = {
currentPage: 1,
eventsPerPage: 10,
active: null,
};
this.handleClick = this.handleClick.bind(this);
this.myStyle = this.myStyle.bind(this);
}

Related

Not rendering JSX from function in React

The function is getting the value of a button click as props. Data is mapped through to compare that button value to a key in the Data JSON called 'classes'. I am getting all the data correctly. All my console.logs are returning correct values. But for some reason, I cannot render anything.
I've tried to add two return statements. It is not even rendering the p tag with the word 'TEST'. Am I missing something? I have included a Code Sandbox: https://codesandbox.io/s/react-example-8xxih
When I click on the Math button, for example, I want to show the two teachers who teach Math as two bubbles below the buttons.
All the data is loading. Just having an issue with rendering it.
function ShowBubbles(props){
console.log('VALUE', props.target.value)
return (
<div id='bubbles-container'>
<p>TEST</p>
{Data.map((item,index) =>{
if(props.target.value == (Data[index].classes)){
return (
<Bubble key={index} nodeName={Data[index].name}>{Data[index].name}
</Bubble>
)
}
})}
</div>
)
}
Sandbox Link: https://codesandbox.io/embed/react-example-m1880
import React, {Component} from 'react';
import ReactDOM from 'react-dom';
const circleStyle = {
width: 100,
height: 100,
borderRadius: 50,
fontSize: 30,
color: "blue"
};
const Data = [
{
classes: ["Math"],
name: "Mr.Rockow",
id: "135"
},
{
classes: ["English"],
name: "Mrs.Nicastro",
id: "358"
},
{
classes: ["Chemistry"],
name: "Mr.Bloomberg",
id: "405"
},
{
classes: ["Math"],
name: "Mr.Jennings",
id: "293"
}
];
const Bubble = item => {
let {name} = item.children.singleItem;
return (
<div style={circleStyle} onClick={()=>{console.log(name)}}>
<p>{item.children.singleItem.name}</p>
</div>
);
};
function ShowBubbles(props) {
var final = [];
Data.map((item, index) => {
if (props.target.value == Data[index].classes) {
final.push(Data[index])
}
})
return final;
}
function DisplayBubbles(singleItem) {
return <Bubble>{singleItem}</Bubble>
}
class Sidebar extends Component {
constructor(props) {
super(props);
this.state = {
json: [],
classesArray: [],
displayBubble: true
};
this.showNode = this.showNode.bind(this);
}
componentDidMount() {
const newArray = [];
Data.map((item, index) => {
let classPlaceholder = Data[index].classes.toString();
if (newArray.indexOf(classPlaceholder) == -1) {
newArray.push(classPlaceholder);
}
// console.log('newArray', newArray)
});
this.setState({
json: Data,
classesArray: newArray
});
}
showNode(props) {
this.setState({
displayBubble: true
});
if (this.state.displayBubble === true) {
var output = ShowBubbles(props);
this.setState({output})
}
}
render() {
return (
<div>
{/* {this.state.displayBubble ? <ShowBubbles/> : ''} */}
<div id="sidebar-container">
<h1 className="sidebar-title">Classes At School</h1>
<h3>Classes To Search</h3>
{this.state.classesArray.map((item, index) => {
return (
<button
onClick={this.showNode}
className="btn-sidebar"
key={index}
value={this.state.classesArray[index]}
>
{this.state.classesArray[index]}
</button>
);
})}
</div>
{this.state.output && this.state.output.map(item=><DisplayBubbles singleItem={item}/>)}
</div>
);
}
}
ReactDOM.render(<Sidebar />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.0.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.0.0/umd/react-dom.production.min.js"></script>
<div id="root"></div>
The issue here is ShowBubbles is not being rendered into the DOM, instead (according the sandbox), ShowBubbles (a React component) is being directly called in onClick button handlers. While you can technically do this, calling a component from a function will result in JSX, essentially, and you would need to manually insert this into the DOM.
Taking this approach is not very React-y, and there is usually a simpler way to approach this. One such approach would be to call the ShowBubbles directly from another React component, e.g. after your buttons using something like:
<ShowBubbles property1={prop1Value} <etc...> />
There are some other issues with the code (at least from the sandbox) that you will need to work out, but this will at least help get you moving in the right direction.

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

Hide element onClick React based on Id

I have a list of 3 filters that will show based on their id, when clicked it will show the filters matching the id but I would like to hide it if clicked again. So if Filter 1 is clicked it should show and then if clicked again it should hide
https://www.webpackbin.com/bins/-KpFE0uZN94N_RY2lavn
import React, { Component } from 'react'
export default class Catalogue extends Component {
constructor(props) {
super(props)
this.state = {
filterListShow: false,
active: false
}
this.handleShowFilterList = this.handleShowFilterList.bind(this)
}
// Show Filter checklist onClick
handleShowFilterList(id) {
this.setState({
filterListShow: id,
active: false })
}
render() {
const { filterListShow } = this.state
let test = ''
if (filterListShow === 1) {
test = (<div>show 1</div>)
}
else if (filterListShow === 2) {
test = (<div>show 2{console.log(2)}</div>)
}
else if (filterListShow === 3) {
test = (<div>show 3{console.log(3)}</div>)
}
return (
<div >
<div onClick={()=> this.handleShowFilterList(1)}>
Show Filter 1
</div>
<div onClick={()=> this.handleShowFilterList(2)}>
Show Filter 2
</div>
<div onClick={()=> this.handleShowFilterList(3)}>
Show Filter 3
</div>
{test}
</div>
)
}
}
Just add another check in the onClick handler to check whether the current state is the same as the id of the element clicked,
// Show Filter checklist onClick
handleShowFilterList(id) {
if(this.state.filterListShow !== id) {
this.setState({
filterListShow: id,
active: false })
} else {
this.setState({filterListShow: false})
}
}
DEMO
Simply put the condition in handleShowFilterList function, if same item has been clicked again then reset the state value of filterListShow variable.
Like this:
handleShowFilterList(id) {
this.setState(prevState => ({
//if same then reset otherwise assign new id
filterListShow: prevState.filterListShow == id ? false : id,
active: false
}))
}
Working Code.

ReactJs how to show list with load more option

I am tring to show todo list with load more option. I am appling limit.Limit is apply to list.But when i add loadmore()function. then i get error this.state.limit is null Wher i am wrong.Any one can suggest me.
here is my code
todoList.jsx
var TodoList=React.createClass({
render:function(){
var {todos}=this.props;
var limit = 5;
function onLoadMore() {
this.setState({
limit: this.state.limit + 5
});
}
var renderTodos=()=>{
return todos.slice(0,this.state.limit).map((todo)=>{
return(
<Todo key={todo.todo_id}{...todo} onToggle={this.props.onToggle}/>
);
});
};
return(
<div>
{renderTodos()}
<a href="#" onClick={this.onLoadMore}>Load</a>
</div>
)
}
});
module.exports=TodoList;
Changes:
1. First define the limit in state variable by using getInitialState method, you didn't define the limit, that's why this.state.limit is null.
2. Define all the functions outside of the render method.
3. Arrow function with renderTodos is not required.
4. Use this keyword to call the renderTodos method like this:
{this.renderTodos()}
Write it like this:
var TodoList=React.createClass({
getInitialState: function(){
return {
limit: 5
}
},
onLoadMore() {
this.setState({
limit: this.state.limit + 5
});
},
renderTodos: function(){
return todos.slice(0,this.state.limit).map((todo)=>{
return(
<Todo key={todo.todo_id}{...todo} onToggle={this.props.onToggle}/>
);
});
};
render:function(){
var {todos} = this.props;
return(
<div>
{this.renderTodos()}
<a href="#" onClick={this.onLoadMore}>Load</a>
</div>
)
}
});
This is witout button click.
As you all know react components has a function componentDidMount() which gets called automatically when the template of that component is rendered into the DOM. And I have used the same function to add the event listener for scroll into our div iScroll.
The scrollTop property of the element will find the scroll position and add it with the clientHeight property.
Next, the if condition will check the addition of these two properties is greater or equal to the scroll-bar height or not. If the condition is true the loadMoreItems function will run.
class Layout extends React.Component {
constructor(props) {
super(props);
this.state = {
items: 10,
loadingState: false
};
}
componentDidMount() {
this.refs.iScroll.addEventListener("scroll", () => {
if (this.refs.iScroll.scrollTop + this.refs.iScroll.clientHeight >=this.refs.iScroll.scrollHeight){
this.loadMoreItems();
}
});
}
displayItems() {
var items = [];
for (var i = 0; i < this.state.items; i++) {
items.push(<li key={i}>Item {i}</li>);
}
return items;
}
loadMoreItems() {
this.setState({ loadingState: true });
setTimeout(() => {
this.setState({ items: this.state.items + 10, loadingState: false });
}, 3000);
}
render() {
return (
<div ref="iScroll" style={{ height: "200px", overflow: "auto" }}>
<ul>
{this.displayItems()}
</ul>
{this.state.loadingState ? <p className="loading"> loading More Items..</p> : ""}
</div>
);
}
}
This is example

How do I assign CSS class based on state variable's value in ReactJS

Im coding up a project in ReactJS. Ive got some divs that can be clicked by user. By default every div's background color should be set to green, but after the click it should become red (meaning that this specific div has been already clicked and further clicking on it won't make any difference). My idea for setting the CSS class is that inside className I've got a ternary if statement based on corresponding value from the array. The solution I've presented doesn't do anything, no errors are popping up. How can I achieve my goal?
Code:
var style = require('./board.css');
var React = require('react');
class board extends React.Component {
constructor(props) {
super(props);
this.handleClick = this.handleClick.bind(this);
this.state = {
fieldClicksArray: [
false, false, false,
false, false, false,
false, false, false
]
}
}
handleClick(index) {
if (this.state.fieldClicksArray[index] === false) {
this.state.fieldClicksArray[index] = true;
}
render () {
return (
<div className="parent">
<div className={this.state.fieldClicksArray[0] ? 'red' : 'green'} onClick={() => this.handleClick(0)}>1</div>
</div>//parent
)//return
}//render
}//class
export default board;
The CSS:
.red {
background-color: red;
}
.green {
background-color: green;
}
You need to use setState(). And clone the array so that you don't mutate the previous state. Finally, it is better to use the functional form of setState() when your next state is calculated from previous state.
handleClick(index) {
this.setState((prevState) => {
// make a copy
let fieldClicksArray = prevState.fieldClicksArray.slice();
// change one item
fieldsClickArray[index] = true;
// return next state to be merged
return { fieldsClickArray };
});
}
Read more: https://facebook.github.io/react/docs/state-and-lifecycle.html#using-state-correctly
Hope this helps!
class Board extends React.Component {
constructor(props) {
super(props);
this.handleClick = this.handleClick.bind(this);
this.state = {
fieldClicksArray: [
false, false, false,
false, false, false,
false, false, false
]
}
}
handleClick(index) {
if (this.state.fieldClicksArray[index] === false) {
var newArray = this.state.fieldClicksArray;
newArray[index] = true;
this.setState({
fieldClicksArray: newArray
})
}
}
render(){
return(
<div className="parent">
<div className={this.state.fieldClicksArray[0] ? 'red' : 'green'} onClick= {()=>this.handleClick(0)}>1</div>
</div>//parent
)//return
}//render
}//class
ReactDOM.render(<Board />, document.getElementById("app"))
.red {
background-color: red;
}
.green {
background-color: green;
}
<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="app"></div>
this.state.fieldClicksArray[index] = true; wont perform anything. you need to call this.setState to change the state of your component.
handleClick(index) {
if (this.state.fieldClicksArray[index] === false) {
var newArray = this.state.fieldClicksArray;
newArray[index] === false;
this.setState({
fieldClicksArray: newArray
})
}
Also to use setState method in your click handler, you'll need to bind your function to the component,
render () {
return (
<div className="parent">
<div className={this.state.fieldClicksArray[0] ? 'red' : 'green'} onClick= {()=>this.handleClick(0)}>1</div>
</div>//parent
)//return
}

Categories

Resources