`export default function Ratings(props){
const[hover,setHover] =useState(false); // checks for hover state
const [com, setCom] = useState(false); //checks for click state
function isHover(){
setHover(true);} //connects to onMouseOver event then sets the hover state
function isNotHover(){ //connects to onMouseLeave event then sets the hover state
setHover(false);}
function op(){ //Send the Id of the rating button back to app.js so
props.op(props.id);} // it can be then forwarded to another page
function designs(){ //connects the click to sate, if the state is true it makes it false
com ? setCom(false):setCom(true)} // and vice verca
function bth(){ // I have two functions on click so this combines both
op() //the functions and gives it as one to the clicke event
designs()}
pressed //is style after clicked
rateStyle //is style before clicked
return(
<div style={hover|| com ? pressed: rateStyle} onMouseOver={isHover}
onMouseLeave={isNotHover} onClick={bth} >
{props.valN}
</div>)
}`I have five rating buttons and I want to unclick the already clicked button when another one is clicked. By clicking I mean, When I click one of the buttons their style is changed mainly background colour now I want when somebody presses another rating I want the style for the previously clicked button to go back to normal and the newly pressed button to go to active state help.
I used this method for this question.
inside your button
<button id="button" onClick={
(e) => {
if(res === "unpressed"){
//if button is pressed for first
//time
e.target.style.backgroundColor ="rgb(195, 197, 64)";
setRes(pressed);
//Update res into false
}else{
//if button is pressed for second
//time
e.target.style.backgroundColor ="rgb(195, 17, 64)";
setRes(unpressed);
//Update res into false
}
}
}>
STAR
</button>
using Hooks
import { useState } from "react";
const [res,setRes] = useState("unpressed");
Related
<section key={i}>
<input
type='radio'
key={attribute.name + item.id}
id={attribute.name + item.id}
name={attribute.name}
value={item.value}
defaultChecked={i === 0}
onClick={(event) => inputClick(attribute, event)}
/>
<label
htmlFor={attribute.name + item.id}
>
{
item.value
}
</label>
</section>
The code above is more or less what a .map() function is supposed to return in my React.js APP, creating input radio buttons for customizing a product before adding it to the cart state. All I did was remove some classes, etc. that were there for CSS purposes, etc.
Ideally, what is supposed to happen here is that...
When rendering the product page for the first time, the very first input radio button that is returned by .map() should be checked by default. This works thanks to the "defaultChecked" attribute. No problems here.
After I click a different input radio button (not the "defaultChecked" one), the checked input should change and all the other inputs should be left unchecked. As I understand it, input radio buttons with the same 'name' attribute do this automatically.
When clicking the input radio button, the "onClick" function should trigger. This is where the code is not functioning as I wish it would.
The issue is that when my page renders for the first time and I click on an input radio button (other than the "defaultChecked") the "onClick" function does not trigger. It only triggers when I have clicked on a different input once and then on another.
A.k.a. it triggers on the second click. After that second click, it works as intended - every time a different input radio button is selected/clicked on - the function triggers, but not for the very first time.
I tested this with console.log("I am triggered") at the end of the "onClick" "inputClick(attribute, event)" function, and only on the second click would the console log "I am triggered".
I was able to fix the issue by removing the "defaultChecked" attribute. I think the issue might be tied to the fact that the "onClick" function is only able to be triggered when one input gains the "checked" attribute and another loses it, but the "defaultChecked" attribute does not count as an input being "fully checked" or something like that.
I could leave it at that, but the project that I am working on required me to have a default checked input radio button on the first-page render. So, I can't just delete the "defaultChecked" attribute and call it a day.
Any ideas on what could be causing this behavior?
UPDATE1
The following is the body of the inputclick() function:
//* Handle input selection
const inputClick = (attribute, event) => {
//* Parse state
let state = JSON.parse(JSON.stringify(itemState));
//* Get all the required values from the clicked input
const attributeId = attribute.id;
const itemTargetValue = event.target.value;
//* Check if the attribute is in state
const attributeIs = state.some(item => item.id === attributeId);
//* If the attribute does not exsist - add the attribute to state
if(attributeIs === false) {
const obj = {
id: attributeId,
selectedItem: itemTargetValue
};
state.push(obj);
return setitemState(state);
}
//* If the attribute id already exsists in state
if(attributeIs) {
//* Find the index of the attribute in question
const attributeIndex = state.map(object => object.id).indexOf(attributeId);
const attributeInQuestion = state[attributeIndex].selectedItem;
//* If the attribute's item's id is the same as the seelected input - do nothing
if(attributeInQuestion === itemTargetValue) {
return
}
//* If the attribute's item's id is not the same - change it to the new value
if(attributeInQuestion !== itemTargetValue) {
state[attributeIndex].selectedItem = itemTargetValue;
console.log(state);
return setitemState(state);
}
}
};
Here is the working code that fixes the issue.
Yes, there is some streamlining, for example, code shortening, etc. Yet, the difference that solves the issue is that...
The code that I had posted in the question originally was working. Meaning, that it was firing the inputClick() function and changing which input was selected, the problem was that...
...the defaultChecked logic in the was preventing the chosen input from being rendered as a selected input a.k.a. to change its CSS styling.
Bellow is the new onClick() function.
//* Handle input selection
const inputClick = (product, attribute, event) => {
let newCart = JSON.parse(JSON.stringify(cartState));
const productId = product.id;
const attributeId = attribute.id;
const itemTargetValue = event.target.value;
//* Find the product in cart state */
const productIndex = newCart.map((object) => object.id).indexOf(productId);
//* Find the attribute by id in question */
const attributeIndex = newCart[productIndex].selectedAttributes.map(object => object.id).indexOf(attributeId);
//* Change the products selected attribute item */
newCart[productIndex].selectedAttributes[attributeIndex].selectedItem = itemTargetValue;
setcartState(newCart);
};
Below is what the "inside" of the looks like now.
<input
type='radio'
key={product.id + attribute.name + item.id}
id={product.id + attribute.name + item.id}
name={product.id + attribute.name}
value={item.value}
defaultChecked={product.selectedAttributes[selectedId].selectedItem === item.value}
onChange={(event) => inputClick(product, attribute, event)}
>
</input>
When a button (material ui) is clicked for a second time, I want that button to be disabled (disabled={true}). I did not find any example related to this on StackOverflow.
<Button
onClick={this.startDraw.bind(this)}
disabled={}
startIcon={<Brush />}
>
At first, the button is clickable. When it is clicked, something happens, but when this same button is clicked a second time, the button should be disabled (cannot be clicked anymore).
For Class component use
state = {
count: 0
};
this.setState({ count: count + 1 }); // use this on your button click
and for the button part
<Button
onClick={this.startDraw.bind(this)}
disabled={state.count == 2}
startIcon={<Brush />}
/>
for functional component use this approach
const [count , setCount ] = useState(0);
setCount(count + 1) // use this on your button call
<Button
onClick={this.startDraw.bind(this)}
disabled={count == 2}
startIcon={<Brush />}
/>
I've currently implemented custom markers on the map using the following code:
// extend mapboxGL class so we can edit the click function
class CustomMarker extends mapboxgl.Marker {
// new method onClick, sets _handleClick to a function you pass in
onClick(handleClick) {
this._handleClick = handleClick;
return this;
}
// the existing _onMapClick was there to trigger a popup
// but we are hijacking it to run a function we define
_onMapClick(e) {
const targetElement = e.originalEvent.target;
const element = this._element;
if (this._handleClick && (targetElement === element ||
element.contains((targetElement)))) {
this._handleClick();
}
}
};
const el1 = document.createElement('div');
el1.id = "marker1";
el1.style.marginTop = '-'+(36/2)+'px';
// make a marker and add it to the map
new CustomMarker(el1)
.onClick(() => { //when clicked, define the following function
console.log(1+1);
})
.addTo(map);
I have then added a html button to navigate between markers(i.e next and previous) which then calls something like document.getElementByID("marker1").click() once clicked.
This button works normally and triggers the marker click, however when I click on the mapbox map once (a single click anywhere on the map), document.getElementByID("marker1").click() does not seem to get called when I click the html button. If I drag the map or double click to zoom in after however, the html button starts to work again. Does anyone know why this is happening?
Something very confusing you have made. Actually MapBox Marker does not have click event, but its Element does. So to make things work, you need to use the following:
marker.getElement().addEventListener('click', function(event: PointerEvent) {
event.stopPropagation(); // to prevent map click event from triggering as well
...
});
i have a function that calculates pages and page buttons based on an api. Inside the buttons get rendered and they have an onClick function. When i click the button, this is supposed to happen:
sets the current page number and writes it into state
calls the api which gets text elements to display according to current page
evaluates page buttons and numbers based on api and marks the current page with a css class
event handler:
handleClick(event) {
let currentPage = Number(event.target.id)
localStorage.setItem("currentPage", currentPage)
this.setState ({
currentPage: currentPage
})
this.fetchApi()
}
then i'm returning the component that deals with pages:
return(
<div>
<Paging
data = {this}
currentPage = {this.state.currentPage}
state = {this.state}
lastPage = {this.state.lastPage}
handleClick = {this.handleClick}
/>
</div>
)
and the component looks like this:
function Paging(props) {
const apiPaging = props.state.apiPaging
const apiPagingSliced = apiPaging.slice(1, -1)
const renderPageNumbers = apiPagingSliced.map((links, index) => {
return <button key={index} id={links.label}
onClick={(index)=>props.handleClick(index)}
className={(links.active ? "mark-page" : "")}
>{links.label} {console.log(links.label) }
</button>
})
return (
<div id = "page-nums">
{renderPageNumbers}
</div>
)
So what happens is that Paging() function gets called twice. There is a handy value inside the api called "active" (links.active) which is a boolean, and if set to true, means that the page is the current page. i then add a class "mark-page" on to highlight that i'm currently on that page. If i {console.log(links.label)} i see that it's invoked twice, first being the correct values and second being the previously clicked values. So it works correctly only if i reload the page again.
i.e if i click page 2,it stays on page 1 and marks page 1. if i then click page 3, it marks page 2. and (afaik) Paging() gets only invoked once, at the end of my only class (Body).
I've been at it yesterday and today and have no idea anymore.
change your handleClick function to this.
handleClick(event) {
window.scrollTo({
top: 0,
behavior: 'smooth',
});
if (event.target.id >= 1) {
let currentPage = Number(event.target.id);
localStorage.setItem('currentPage', currentPage);
this.setState({
currentPage: JSON.parse(localStorage.getItem('currentPage')),
},()=>{
this.fetchApi();
});
}
}
in your fetchApi function you reference currentPage as below.
const apiQuery = JSON.parse(this.state.currentPage);
But it hasn't updated yet.
see https://reactjs.org/docs/react-component.html#setstate
I have made a component where I am rendering grids of items. On clicking one item, the item is being selected. However there are many items present so there is scroll bar. Whenever I click on an Item, the component is re-rendered (as I am putting the selectedItem in my state), which further re-renders all the other items. But when I click an item after scrolling to the bottom (or middle), the component renders to the top, however I want that to remain on the position it was being clicked.
The components are as follows :
Full-Screen (made using react-portal, contains onClick and changes its state)
--TilesView (all tiles wrapper which renders all the tiles and has an ajax call)
--all Tiles (single tile element)
The part code is as follows :
FullScreen:
componentDidMount() {
if (this.props.selectedPost) {
this.setState({
selectedPost: {
[this.props.selectedPost[0]]: true
}
});
}
}
render() {
const that = this;
//Todo: User fullpage header when space is updated
return (
<Portal container={() => document.querySelector('body')}>
<div className={styles.container}>
<FullPageForm onHide={that.props.onCancel} closeIcnLabel={'esc'} bgDark={true}>
<FullPageForm.Body>
<span className={styles.header}>{'Select Post'}</span>
<div className={styles.body}>
<ExistingAssets onCreativeTileClicked={this.handlePostClick}
selectedCreatives={this.state.selectedPost}
showSelectedTick/>
</div>
</FullPageForm.Body>
</FullPageForm>
</div>
</Portal>
);
}
handlePostClick = (adCreativeAsset, id) => {
event.preventDefault();
this.setState({
selectedPost: {
[id]: adCreativeAsset
}
});
}
In my handlePostClick, I tried doing event.preventDefault() but it didn't work. I have no clue why this is happening, thanks in advance.
Try changing your handlePostClick definition to
handlePostClick = (e, adCreativeAsset, id) => {
e.preventDefault();
//blah blah what you want
}
and in your JSX change onCreativeTileClicked={this.handlePostClick} to onCreativeTileClicked={this.handlePostClick.bind(this)}.
The event you were prevent-defaulting (stopping propagation in real terms) isn't the real event coming from the click but a synthetic one that can be summoned to fill in for an event when there isn't one. You need to stop propagation for the real event.
Hope this helps.