Javascript mouseDown - cannot read currentTarget of undefined - javascript

I have a composent with which I would allow maintaining click in order to call multiple function by push-holding. My action dispatch a simple function to Redux reducers.
The objective of my component is to allow people decrease quantity of their order by maintaining a mouse's click. So that it, to allowing visitors have a more fluent user experience.
When I trigger the function my console returns me :
Cannot read property 'currentTarget' of undefined
When I click alone one time it is great. But when I mouseDown it fails with the above message.
Here my reactComponent.js:
import React, {Component} from 'react'
import style from "./OrderRibbon.css";
import equal from 'deep-equal';
export default class OrderRibbon extends Component {
t;
start = 100;
decreaseQuantity = (e) => {
e.preventDefault();
this.props.decreaseOrder(this.props.id)
}
addOrder= (e) => {
e.preventDefault();
this.props.addOrder(this.props.id)
}
orderPushing = (e) => {
e.preventDefault();
this.orderRepeat(e);
}
orderRepeat = (e) => {
if( e.currentTarget.attributes.name.value ){
console.log("EVENT NAME IN ORDER REAPEAT: ", e.currentTarget.attributes.name.value)
}else{
console.log("EVENT NAME IN ORDER REAPEAT: ", e.target.attributes.name.value)
}
if(e.currentTarget.attributes.name.value === "addOrder"){
this.addOrder
}else{
this.decreaseQuantity
}
this.t = setTimeout(this.orderRepeat, this.start);
this.start = this.start / 2;
}
// STOP Calling function
onMouseUp = () => {
clearTimeout(this.t);
this.start = 100;
}
render(){
return (
<div className={style.order_ribbon_layout} >
<div className={`${style.title} ${style.details_element}`} >
{this.props.title}
<div className={style.quantity} >
<div className= {style.quantity_icon}></div>
<span className= {style.quantity_number} > {this.props.quantity} </span>
</div>
</div>
<div className={style.price} >
{this.props.price * this.props.quantity}
</div>
<div className={style.quantity} >
<div
onMouseUp={this.onMouseUp}
onMouseDown={this.orderPushing}
name="decreaseQuantity"
onClick={this.decreaseQuantity}
className={ `${style.cardButton}`}
id={style.decreaseQuantity}></div>
<div
onMouseUp={this.onMouseUp}
onMouseDown={this.orderPushing}
name="addOrder"
onClick={this.addOrder}
className={ `${style.addButon}`}
// ${style.details_element}
id={style.addArticle}></div>
</div>
</div>
)
}
}
I wcan't figure out what is going wrong, if any body have an hint, would be great.

You have event binding issue. You can define like this:
orderPushing = () => (e) => {
e.preventDefault();
this.orderRepeat(e);
}
Or, keeping the same as you currently have, you may use inline event binding like this:
onMouseDown={(e) => this.orderPushing(e)}

Related

Function does not work when I go to the page back, and then return to the page (React)

function Final_Set(){
return(
<div id="exercise_sets_decider_box">
{
(function(){
console.log(1);
Final_set_page();
})()
}
</div>
);
function App(){
const [mode, Setmode] = useState("0");
if (mode === "0"){
$(document).on('click', "#purple_box_1", function(e){
Setmode("Final");
});
return(
<div id="purple_box_1">
</div>
);
} else if(mode==="Final"){
$(document).on('click', "#purple_box_2", function(e){
Setmode("0");
});
return(
<div>
<Final_Set></Final_Set>
<div id="practice"></div>
<div id="purple_box_2">
</div>
</div>
)
}
}
In brief, Final_set_page function is appending html code in div:#practice, like $("#practice").append('blahblah'). If I go from mode '0' to mode 'Final', Final_set_page() is well working. But if I return to mode '0' and go back to mode 'Final', console.log() is well working but Final_set_page() is not working. I don't know the reason, and I can't find the solution. Please help!
Maybe the problem is in jQuery.
I have rewritten the code. Maybe edit this code instead according to your needs.
By the way, we have no idea what Final_set_page is...
function Final_Set() {
useEffect(() => {
console.log(1);
Final_set_page(); // I don't know what it is, so leaving it here. Move it if it is a component.
}, []); // [] empty dependency array means useEffect only runs once.
return (
<div id="exercise_sets_decider_box">
exercise_sets_decider_box
</div>
);
}
function App() {
const [mode, setMode] = useState("0"); // SetMode does not follow the convention for naming variables.
const handlePurpleBox1Click = () => setMode("Final"); // I moved this to separate functions so it is easier for you to edit them further.
const handlePurpleBox2Click = () => setMode("0");
if (mode === "0") {
return (
<div id="purple_box_1" onClick={handlePurpleBox1Click}>
purple_box_1
</div>
);
}
if (mode === "Final") { // if the previous return worked, this code is not reachable. This looks cleaner to me.
return (
<div>
<Final_Set></Final_Set>
<div id="practice"></div>
<div id="purple_box_2" onClick={handlePurpleBox2Click}>
purple_box_2
</div>
</div>
)
}
return <></> // add this, so the component returns something just in case.
}

How to simulate long press with react js?

I want to trigger long press event with click event. is there any way to that in react js?
something close to this, is the jQuery trigger() function. but i want something like trigger("longPress") or open up right click menu with left click in react. both mentioned (long press trigger / open up right click menu) are ideal for me
you can do this hack by get hold time
https://stackblitz.com/edit/react-d1txdm
export default function App() {
let triggerTime;
return (
<div>
<h1>Try on Google Chrome Desktop</h1>
<p>Open the console log to see how the event gets triggered.</p>
<p>The event should not get triggered if there is a long click.</p>
<img
src="https://via.placeholder.com/200.png/09f/fff"
onClick={(e) => {
if (triggerTime > 1000) return;
else console.log('normal click');
}}
onMouseDown={() => {
triggerTime = new Date().getTime();
}}
onMouseUp={() => {
let thisMoment = new Date().getTime();
triggerTime = thisMoment - triggerTime;
}}
/>
</div>
);
}
What about something like this:
const myComponent = () => {
let clickHoldTimer = null;
const handleMouseDown = () => {
clickHoldTimer = setTimeout(() => {
//Action to be performed after holding down mouse
}, 1000); //Change 1000 to number of milliseconds required for mouse hold
}
const handleMouseUp = () => {
clearTimeout(clickHoldTimer);
}
return (
<div onMouseDown={handleMouseDown} onMouseUp={handleMouseUp} />
)
}

React Js AwesmeSlider Autoplay

Hey im a bit new to React. I found this slider which I have implemented and it works fine.
https://caferati.me/demo/react-awesome-slider
My only issue now is I would like it to Autoplay but it seems I cant wrap my head around it. As I understand I need to make a function which will do it for me?
My code so far is.
class Slider extends Component {
render() {
return (
<div className="slider">
<AwesomeSlider cssModule={styles} onFirstMount={slider}>
<div data-src={image2}>
<div className="sliderText">
<div>
<h1>Text For first sike</h1>
<NewsletterButton className="clickMe" text={I18n.t('ClickMe')}/>
</div>
</div>
</div>
<div data-src={image4}>
<Fade left duration={2300}>
<img className="sliderImage2" src={image3}/>
</Fade>
<Zoom duration={2000}>
<div className="sliderText2">
<h1> Text For Slide2 </h1>
<p>Slide 2 Paragraph</p>
</div>
</Zoom>
</div>
<div data-src={image4}>
<Zoom duration={2000}>
<div className="sliderText3">
<h1> Slide3 </h1>
<p>Slider 3 paragrah</p>
</div>
</Zoom>
<Fade bottom duration={2300}>
<img className="sliderImage3" src={image1}/>
</Fade>
</div>
</AwesomeSlider>
</div>
);
}
}
export default Slider;
You can give the below approach a try:
Create a timer (as you are looking for an autoplay) which runs for every 2 seconds or so and call a method named setNextImage in it.
In your componentDidUpdate(),
setTimeout(this.setNextImage, 2000);
In your method write some logic to update state.
setNextImage: function() {
// setState method is used to update the state
let index = this.state.currentIndex;
if(index == yourMax_Image_Count)
index == 1
this.setState({ : this.state.currentIndex -1 });
},
I see there is a attribute selected in AwesomeSlider and you can set this.state.currentIndex as its value
Make sure you are handling timeout properly.
You can get next button with jQuery and use click() function like this
$(document).ready(function () {
setInterval(function() {
$(".button_class").click();
}, 10000);
});
componentDidMount() {
const interval = setInterval(this.handleNextSlide, 12500);
this.interval = interval; }
componentWillUnmount() {
if (this.interval != null) {
clearInterval(this.interval);
} }
handleNextSlide = () => {
const { dataSource } = this.props;
const { currentIndex } = this.state;
if(currentIndex == (dataSource && dataSource.length) - 1) {
this.setState({
currentIndex: 0
});
} else {
this.setState({
currentIndex: this.state.currentIndex + 1
});
} }
render() {
const { dataSource } = this.props;
const { currentIndex } = this.state;
return (
<AwesomeSlider
selected={currentIndex}
cssModule={AwsSliderStyles}
>
{dataSource && dataSource.map((value, key) => {
return (
//Do some stuff.
);
})}
</AwesomeSlider>
);
}
try this by importing "withautoplay"
import withAutoplay from 'react-awesome-slider/dist/autoplay'
const AutoplaySlider = withAutoplay(AwesomeSlider)
and use autoplay tag in your component
<AutoplaySlider
play
cancelOnInteraction={false} // should stop playing on user interaction
interval={6000}
>
<div data-src=/path/to/image.png />
<div data-src=/path/to/image.png />
<div data-src=/path/to/image.png />
</AutoplaySlider>
you can follow this link for more details https://www.npmjs.com/package/react-awesome-slider

React - Button Pressed, keep calling function

I'm trying to implement a zoom function. onClick works fine, but I'd like to have it when I hold the zoom button down, it zooms continuously. How can I implement this with ReactJS?
Jquery: mousedown effect (while left click is held down)
I was using this as a template, but onMousedown doesn't get registered according to console.log
<div className="zoomControl" >
<button className="zoomIn" onMouseDown={this.zoomIn}>+</button>
<button className="zoomOut" onClick={this.zoomOut}>-</button>
</div>
zoomIn = () => {
console.log('test');
var self = this;
this.timeout = setInterval(function(){
// Do something continuously
this.renderer.zoomIn();
}, 100);
return false;
};
zoomMouseUp = () => {
clearInterval(this.timeout);
return false;
};
You need to use both mouseUp and mouseDown. Start a time on mouseDown and call the zoom function with the timeout repeatedly and clear the time on mouseUp.
Here a demo with zoomIn and zoomOut to compare and better understand the algorithm.
Hope this helps!!
class Zoom extends React.Component {
constructor(props) {
super(props)
this.state = {
zoom: 1,
}
this.t = undefined
this.start = 100
this.repeat = this.repeat.bind(this)
this.onMouseDown = this.onMouseDown.bind(this)
this.onMouseUp = this.onMouseUp.bind(this)
this.zoom = this.zoom.bind(this)
this.zoomOut = this.zoomOut.bind(this)
}
zoom(){
this.setState({zoom: this.state.zoom + 0.1})
}
repeat() {
this.zoom()
this.t = setTimeout(this.repeat, this.start)
this.start = this.start / 2
}
onMouseDown() {
this.repeat()
}
onMouseUp() {
clearTimeout(this.t)
this.start = 100
}
zoomOut(){
this.setState({
zoom: 1
})
}
render() {
return <div className="zoomControl" >
<div className="zoom" style={{transform: 'scale('+ this.state.zoom +')'}}></div>
<button className="zoomIn" onMouseUp={this.onMouseUp} onMouseDown={this.onMouseDown}>+</button>
<button className="zoomOut" onClick={this.zoomOut}>-</button>
</div>
}
}
ReactDOM.render(<Zoom/>, document.getElementById('app'))
body {
overflow: hidden
}
.zoom {
width: 20px;
height: 20px;
margin: 0 auto;
background: red;
}
<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>
If you have to do some kind of animation here, you're better off using requestAnimationFrame than setting intervals. I'd do it something like this.
class App extends React.Component {
state = {
value: 0,
mousedown: false
}
zoom = () => {
if (this.state.mousedown) {
this.setState({ value: this.state.value + 1},
() => { window.requestAnimationFrame(this.zoom) }
)
}
}
zoomIn = () => {
window.requestAnimationFrame(this.zoom);
}
toggleMouseDown = () => {
this.setState({
mousedown: !this.state.mousedown
});
this.zoomIn()
}
render() {
return(
<div>
<button
onMouseUp={this.toggleMouseDown}
onMouseDown={this.toggleMouseDown}>
Click me
</button>
{/* The rest of your component goes here */}
</div>
);
}
}
It's hard to get all of the context, but I'll try to give a relevant answer:
You don't have any property set to call zoomMouseUp when you release the button. I'd start with:
<button className="zoomIn" onMouseDown={this.zoomIn} onMouseUp={this.zoomMouseUp} onMouseOut={this.zoomMouseUp}>+</button>
You stated that it starts zooming, but doesn't stop. That makes me assume it's working, so that should probably fix it. I added the onMouseOut because if they press the button and move the mouse away without releasing it, it's going to continue.
There are a lot of ways to do this, but that's probably the most simple with what you have.
My issue was due to right click being the primary click or some thing along the lines. It works fine as is.

Mixin functions only work in render()

For some reason, it appears that mixin functions in my code only work properly in render() function. It could be that I'm not calling them in the right manner outside of the render(), but shouldn't it be exactly the same way?
This way everything works fine (but I can't stick with this since I have to add some extra stuff to click handling, at the same time not altering the mixin):
var Row = React.createClass({
mixins: [someMixin]
},
render: function () {
var clickHandler = null;
var btn = null;
if (firstCase) {
clickHandler = this.order(this.props.name, this.props.else);
btn = (<a href="" onClick={clickHandler}>Order</a>);
} else if (secondCase) {
clickHandler = this.noOrder(this.props.name, this.props.else);
btn = (<a href="" onClick={clickHandler}>No order</a>);
}
return (
<div>
{btn}
</div>
);
}
});
But when I do the obvious and include the mixin functions in another function to handle the click - like this - everything fails and even 'test' is not printed in the console:
var Row = React.createClass({
mixins: [someMixin]
},
handleOrderClick(type) {
console.log('test');
if (type == 'order') {
this.order(this.props.name, this.props.else);
} else if (type == 'no-order') {
this.noOrder(this.props.name, this.props.else);
}
},
render: function () {
var clickHandler = null;
var btn = null;
if (firstCase) {
clickHandler = this.handleOrderClick('order');
btn = (<a href="" onClick={clickHandler}>Order</a>);
} else if (secondCase) {
clickHandler = this.handleOrderClick('no-order');
btn = (<a href="" onClick={clickHandler}>No order</a>);
}
return (
<div>
{btn}
</div>
);
}
});
EDIT:
order and noOrder functions look like this:
order: function (name, else) {
return function (event) {
event.preventDefault();
var term = name + '&&ยค%' + else;
Order.order(name, else, period, function (data) {
if (term === (global || window).MAIN_NAME + '.' + (global || window).MAIN) {
$(window).trigger('Name:update');
}
}.bind(this));
}.bind(this);
},
noOrder: function (name, else) {
return function (event) {
event.preventDefault();
if (!this.state.transferModalOpen) {
this.toggleTransferModal();
}
}.bind(this);
}
In order to use this.setState in handleOrderClick you'll have to use the bind method in your render method. Therefore handleOrderClick will become:
handleOrderClick(type, event) {
this.setState({foo: 'bar'});
if (type == 'order') {
this.order(this.props.name, this.props.else)(event);
} else if (type == 'no-order') {
this.noOrder(this.props.name, this.props.else)(event);
}
},
and your render method becomes:
render: function () {
var clickHandler = null;
var btn = null;
if (firstCase) {
clickHandler = this.handleOrderClick.bind(this, 'order');
btn = (<a href="" onClick={clickHandler}>Order</a>);
} else if (secondCase) {
clickHandler = this.handleOrderClick(this, 'no-order');
btn = (<a href="" onClick={clickHandler}>No order</a>);
}
return (
<div>
{btn}
</div>
);
}
You'll notice that the functions that are returned by this.order and this.noOrder are no longer returned by handleOrderClick, but are instead executed immediately. This should provide the effect you desire.
I've put the code in your example into a jsfiddle and it now seems to be working correctly. I've had to change the prop 'else' to 'alt' because 'else' is a reserved word. I've also just applied the mixin to the class directly for simplicity. I have simpilfied the order and noOrder functions as I don't have access to the Order object and we are only interested in them firing at the correct time. I've also added a second button that you can click to flip the cases so the other button is rendered, causing the component to render again. I've added a label that will display which function had been called when the button was last pressed.
for reference, you can find more information about the bind method here.
Hope this helps ^_^

Categories

Resources