I am trying to have a button change color when the user clicks it in React. Each button I am trying to add this functionality to is also updating state. How can I interact with styles AND update state when these buttons are clicked? Here's my crude attempt:
Some HTML:
<div className="searchPrivacyContainer">
<p>USERS CAN SEARCH FOR MY PROJECT:</p>
<div className="searchPrivacySelect">
<div
className="searchPrivacyYes"
onClick={
(holdColor,
function () {
setProposal({ ...proposal, searchable: true });
})
}
>
And this is the most basic version of the function I'm trying to bind. Writing the body of the function should be the straightforward part hopefully, I just don't know how to bind it to the div which is already calling another function:
const holdColor = (event) => {
console.log(event.target.style);
};
I think this part isn't not working as you expecting,
onClick = {
(holdColor,
function() {
setProposal({ ...proposal,
searchable: true
});
})
}
Simple test,
function x(ev){console.log('x', ev)}
function y(ev){console.log('y', ev)}
const listener = (x, y)
listener(123)
Look, first one (x) never got called, So, you might wanna do something like this on your listener.
onClick={(ev) => {
holdColor(ev)
setProposal({ ...proposal,
searchable: true
});
}}
EDIT:
see this working example (it might be helpful), https://codesandbox.io/s/eloquent-wilson-drbbk?fontsize=14&hidenavigation=1&theme=dark
Related
I've made a function, which will be called when a button is clicked. I want to use it for two buttons, but after implementing it, when I click on one button, both get clicked at the same time?
This is the function, which will be called after onClick -
showMore = () => {
this.setState((prevState) => {
return { showMore: !prevState.showMore };
});
};
This is the condition I've used to call those two buttons (I know, I can do something here to make it just two if conditions rather than 4, suggestions?)
if (!this.state.showMore) {
accounts = take(accounts['demo_accounts'], DEFAULT_NO_OF_ACCOUNTS);
}
if (this.state.showMore) {
accounts = accountsData['demo_accounts'];
}
if (!this.state.showMore) {
cardNumbers =
take(cardNumbers['demo_numbers'], DEFAULT_NO_OF_ACCOUNTS);
}
if (this.state.showMore) {
cardNumbers = accountsData['demo_numbers'];
}
And I am using it for 2 buttons, however, both the buttons are getting clicked at the same time, I know I can use an ID for button, but that doesn't seen to work as well.
To sum it up, two questions basically -
How to reduce the 'if' statements?
How to stop both the buttons getting clicked?
Similar answer, but you can set it so that each button has a different ID and attaches to a different event handler, like so:
<button id="btn1">Click me!</button>
<button id="btn2">Me too!</button>
Javascript:
const button1 = document.getElementById("btn1").addEventHandler('click', function);
const button2 = document.getElementById("btn2").addEventHandler('click', function2);
How to reduce the 'if' statements?
Just combine the like conditions. Since all your conditions are basically checking the value of this.state.showMore you really only need 1 single conditional test.
if (this.state.showMore) {
accounts = accountsData['demo_accounts'];
cardNumbers = accountsData['demo_numbers'];
} else {
accounts = take(accounts['demo_accounts'], DEFAULT_NO_OF_ACCOUNTS);
cardNumbers =
take(cardNumbers['demo_numbers'], DEFAULT_NO_OF_ACCOUNTS);
}
How to stop both the buttons getting clicked?
When I want to use a single general click handler across multiple buttons I use a Higher Order Function, which is a function that returns a function. So in this case I create a clickHandler = id => () => this.setState({ [id]: <value> });
This callback takes an id parameter that is used when attaching the callback to the onClick handler of an element, and it is invoked right away and returns a new function that is actually used as the callback with the id saved in the enclosure.
<button onClick={this.clickHandler('a')>Button A</button>
<button onClick={this.clickHandler('b')>Button B</button>
Here is a codesandbox example of a HOF handler
I am trying to add in a credit card form with Stripe Elements (https://stripe.com/docs/stripe-js/reference#other-methods).
Normally I would focus on an element by doing:
$('input[type="tel"]').focus()
However, this doesn't work with the Stripe credit card input. However, the following does work:
$('input[type="tel"]').value='asdf'
So it is grabbing the correct item. How would I focus the cursor on the input item? It seems like it may be inside an iframe, even though I can write a value to it in jquery/javascript.
The element needs to be fully initialized before you can call focus(). Ensure the element is ready with a simple event handler:
element.on('ready', () => {
element.focus()
})
You should use the focus() method on the element that you created and not the div itself.
For example you can have a button that gives focus to the CVC element (assuming split fields) by doing
document.getElementById('give-focus').addEventListener('click', function () {
cardCvcElement.focus();
});
You can see this in action here: https://jsfiddle.net/4c72oyap/
let elements = stripe.elements();
let cardCvcElement = elements.create("cardCvc");
cardCvcElement.mount("#card-cvc-element");
let cvc = document.querySelector("#card-cvc-element");
cardCvcElement.addEventListener("blur", () => {
cvc.style.removeProperty("border");
});
cardCvcElement.addEventListener("focus", () => {
cvc.style.setProperty("border-color","red");
}
});
You can trigger the focus method after your element created when it's ready
Example:
var cardElement = elements.create('cardNumber', { showIcon: true, style: style, classes: elementClasses });
cardElement.mount('#card-element');
cardElement.on('ready', (e) => cardElement.focus());
If you are using Stripe-react-js SDK, here is how to focus:
<CardElement
options={CARD_ELEMENT_OPTIONS}
onReady={(e) => e.focus()}
/>
Link to official docs https://stripe.com/docs/stripe-js/react#element-components
I have two components here, the first one is a table, and I have an on-click event attached to one of the <td>'s in every row that summons a little tooltip-like window:
<td onClick={ () => loadSelectorWindow(p.product_id) }>
{
p.selectorActive &&
<SelectorWindow
cancelWindow={this.cancelSelectorWindow}
product_id={p.product_id}/>
}
</td>
The function bound to the <td> click will search through all products in state and flip a boolean on the selected product to display the tooltip.
loadSelectorWindow = (product_id) => {
this.setState({ products: this.state.products.map( p => {
if (p.product_id == product_id) {
p.variationSelectorActive = true
} else {
p.variationSelectorActive = false
}
return p
})})
}
However, the tooltip also needs a button with a window cancel event linked to it:
// within <SelectorWindow />
<p onClick={ () => {cancelWindow(event)} }> X </p>
This function cycles through state and sets all of the display booleans to false.
cancelSelectorWindow = (event) => {
event.stopPropagation()
this.setState ({ products: this.state.products.map( p => {
p.variationSelectorActive = false
return p
})})
}
Putting breakpoints in the code I can see that the cancel button is correctly calling the cancel function and setting the displayTooltip boolean to false, temporarily. The problem is, the loadSelectorWindow is ALSO getting fired when the cancelWindow button is clicked, and the boolean is set back to true DX.
This is why I attempted to put the event.stopPropagation call in there but obviously something is still calling it. There is no other place in my code that the loadSelectorWindow function is mentioned... Any ideas how I can stop it from getting called?
I forgot to pass event to the cancelWindow callback function. React why is your syntax so confusing sometimes...
Fix:
<p onClick={ (event) => {cancelWindow(event)} }> X </p>
You have one html element nested inside the other, so if you click the inner one then you will receive onClick events for both. So that is what you are getting. You need to redesign the layout of the page so that does not happen.
I have a magento test-shop with onepagecheckout extension. This uses a onepagecheckout.js. There should be added 'click'-event observers to the payment radio buttons. But when clicking on them, nothing happens.
The observers are added to the single input elements while each-ing through them:
addObservers: function () {
$$('input[name="payment[method]"]').each(function (el) {
el.observe('click', function () {
checkout.update({
'review': 1,
'payment-changed': 1
});
});
});
}
The eached elements are, as can be seen in the Chrome debugger and fit to the input-element ids and names:
el = input#p_method_bankpayment.radio
el = input#p_method_paypal_express.radio
el = input#p_method_cashondelivery.radio
el = input#p_method_phoenix_cashondelivery.radio
The update function is calling new content via AJAX when page is loaded, but is not executed and no network-activity can be seen, when events should be fired.
The installation can be seen here: http://5.175.9.22/gp_de/onepagecheckout/
(Put something in the cart/Warenkorb, go to checkout/Zur Kasse, not further)
Can somebody tell me why the observers are not working? Other installations are working with this extensions, what's
Your input elements are hidden by
style="display:none;"
so nobody can click them. If you remove display:none in dev-tools and then click the radio button, an alert 'Click' pops up.
Try to use a change event instead of click
addObservers: function () {
$$('input[name="payment[method]"]').each(function (el) {
el.observe('change', function () {
checkout.update({
'review': 1,
'payment-changed': 1
});
});
});
}
Update:
I've taken a closer look to this. This could not work with a change event, because there are onclick Attributes on each radiobutton. These are not triggered 'onchange'. So try to trigger the (example):
onclick="payment.switchMethod('phoenix_cashondelivery')"
event with something like this
$$('input[name="payment[method]"]').each(function (el) {
el.observe('change', function () {
$(this).simulate('click');
checkout.update({
'review': 1,
'payment-changed': 1
});
});
});
I'm using this simple render function with a few handlers:
render:function(){
return (
<div id="all-highlights" class="highlight-container" onMouseDown={this.drag} onMouseUp={this.dragEnd} onMouseMove={this.moving}>
<div class="highlight">
</div>
</div>
);
}
Within the React.createClass function, using something like: this.removeTheListener function, how would I then remove the specific mouseMove function? Regardless of performance of the mouseMove function, I know that its resource heavy but for what I'm doing its the perfect event.
Is it possible to remove just a specific listener, and then once removed add it back at a different point in time?
As with everything in React, the key is to think declaratively. The simplest way to do this is to store some state corresponding to whether you want the event to be attached. (You might already have such a flag!) Then you can do something like:
onMouseMove={this.state.dragging ? null : this.moving}
and then simply write
this.setState({dragging: true});
in your mousedown handler.
In React, if you want to change something (attribute, listener, etc..), you should force the component to re-render by updating the state. Then you render based on that state.
Here is a piece of code that should work for you:
var DraggableComponent = React.createClass({
getInitialState: function() {
return {
dragging: false
};
},
render: function(){
var onDrag = this.state.dragging ? this.onDrag : null;
return (
<div
className="highlight-container"
onMouseDown={this.dragStart}
onMouseUp={this.dragEnd}
onMouseMove={onDrag}>
<div className="highlight">
{this.props.children}
</div>
</div>
);
},
dragStart: function() {
this.setState({dragging: true});
},
dragEnd: function() {
this.setState({dragging: false});
},
onDrag: function() {
// ...
}
});