Rendering component on long mouse click - javascript

I am trying to render a modal component on a long mouse click. If I just try to fire an alert it works but rendering doesn't seem to do the trick. I am assuming maybe If I have to return? Not quite sure. I created a function handleButtonPressDown to perform this task and the handleButtonRelease to clear interval in the event the user decides not to perform this action.
export class Dropdown extends React.Component<IProps> {
buttonPressTimer: any;
constructor(props: IProps) {
super(props);
this.handleButtonPress = this.handleButtonPress.bind(this);
this.handleButtonRelease = this.handleButtonRelease.bind(this);
}
public render() {
return (
<div style={{ alignSelf: "center" }}>
<ul className="nav nav-pills">
{filteredProbes.length === 0 ? (
<li className="nav-item dropdown ">
<div
className="dropdown-menu show"
x-placement="bottom-start"
style={{
display: "none"
}}
></div>
</li>
) : (
<li className="nav-item dropdown ">
<div
className="dropdown-menu show"
x-placement="bottom-start"
style={{
position: "relative",
willChange: "transform",
top: "5px",
overflowY: "scroll",
maxHeight: "200px",
color: "white"
}}
>
{this.props.searchState.isActive === false
? probes.map(probe => (
<a
onClick={() => this.props.onUpdateSelectedProbe(probe)}
className="dropdown-item"
onMouseDown={this.handleButtonPress}
onMouseUp={this.handleButtonRelease}
>
<div
className="dropdown-divider"
style={{ backgroundColor: "black" }}
></div>
{probe.companyPN}: {probe.description}
</a>
))
: filteredProbes.map(filterprobe => (
<a
onClick={() =>
this.props.onUpdateSelectedProbe(filterprobe)
}
className="dropdown-item"
>
<div className="dropdown-divider"></div>
{filterprobe.companyPN}: {filterprobe.description}
</a>
))}
</div>
</li>
)}
</ul>
</div>
);
}
handleButtonPress() {
this.buttonPressTimer = setTimeout(() => {
{/* Show the modal if showModal is true */}
this.props.modalState.showModal && (
<WedgeGroup
wedgeState={this.props.wedgeState}
onUpdateSelectedWedge={this.props.onUpdateSelectedWedge}
onUpdateShowModal={this.props.onUpdateShowModal}
onUpdateHideModal={this.props.onUpdateHideModal}
modalState={this.props.modalState}
/>
);
}, 1000);
}
handleButtonRelease() {
clearTimeout(this.buttonPressTimer);
}
}

You need to move the code that you have inside setTimeout to render function and use state to render WedgeGroup:
export class Dropdown extends React.Component<IProps> {
...
constructor(props: IProps) {
super(props);
this.state = {
showModal: false
};
...
}
public render() {
const showModal = this.props.modalState.showModal &&
this.state.showModal;
return (
<div style={{ alignSelf: "center" }}>
{
showModal && (
<WedgeGroup
wedgeState={this.props.wedgeState}
onUpdateSelectedWedge={this.props.onUpdateSelectedWedge}
onUpdateShowModal={this.props.onUpdateShowModal}
onUpdateHideModal={this.props.onUpdateHideModal}
modalState={this.props.modalState}
/>
);
}
//..... render other components
</div>
);
}
handleButtonPress() {
this.buttonPressTimer = setTimeout(() => {
this.setState({
showModal: true
})
}, 1000);
}
handleButtonRelease() {
clearTimeout(this.buttonPressTimer);
}
}

It will not render firstly because your are not triggering any mechanism that makes React render.
I'd suggest to you to remove this component from the setTimeout, place it inside the render (where it should be).
And finally manipulate your component state to show or hide your modal.
If you trigger a timer to show the modal view it will only appear after the change of the state, so in your case it will take 1s to show to the user, what may look not responsive.
// inside your handleButtonPress()
this.setState({
showModal: true
}}

Related

How to trigger onClick of focused element by pressing enter in navbar

There is a list of nav items and its focus nav item below each press TAB key,
I need to fire the onClick event of the focused nav item when pressing the ENTER key.
This is what I do,
onKeyPress works as expected but do not trigger onClick
NavBar compoenent:
const Navbar = () => {
...
return (
<nav>
<ul style={{ listStyleType: 'none', padding: 0, margin: 0 }}>
{authenticatedRoutes.map((currentItem: any, index: number) => {
const isOpen = openedDrawer === currentItem.path
return (
<ul
key={`ROUTE_LIST_${index}`}
style={{
listStyleType: 'none',
}}
>
<li key={`ROUTE_${index}`}>
<div
onKeyPress={e => {
if (e.key === 'Enter') {
const event = new MouseEvent('click')
e.target.dispatchEvent(event)
}
}}
onClick={() => {
history.push(currentItem.path)
}}
role="link"
tabIndex={0}
>
<div style={{ display: 'flex', alignItems: 'center' }}>
<div
style={{
...LEFT_BORDER,
backgroundColor: isOpen ? 'transparent' : 'initial',
}}
/>
{linkText}
</div>
</div>
</li>
</ul>
)
})}
</ul>
</nav>
)
You can't programatically trigger native event hooks on a component easily in react.
The best solution would be to put the code in your onKeyPress as well...
onKeyPress={e => {
if (e.key === 'Enter') {
history.push(currentItem.path) // I Added this line
const event = new MouseEvent('click')
e.target.dispatchEvent(event)
}
}}
onClick={() => {
history.push(currentItem.path)
}}

Spring animation is not working in ReactJS

The below Spring animation is not working in ReactJS.
I have a Component class written like this:
import React from "react";
import { Component } from 'react'
import { Spring } from 'react-spring'
export default class Menu extends Component {
constructor(props) {
super(props);
this.state = { isMouseOver: false };
this.handleMouseEnter = this.handleMouseEnter.bind(this);
this.handleMouseLeave = this.handleMouseLeave.bind(this);
}
handleMouseEnter(e) {
this.setState({ isMouseOver: true });
}
handleMouseLeave() {
this.setState({ isMouseOver: false });
}
LogoText(props) {
const isMouseOver = props.isMouseOver;
const handleMouseEnter = props.handleMouseEnter;
const handleMouseLeave = props.handleMouseLeave;
if (isMouseOver) {
return (
<Spring
from={{ opacity: 0 }}
to={{ opacity: 1 }}
>
{
(props) => (
<div style={props}>
hover<!--this renders fine-->
<div className='upperDivLogoText' onMouseEnter={handleMouseEnter} onMouseLeave={handleMouseLeave}>
<span><a href='#' style={{ color: '#d8f3dc' }} >dWare.sk</a></span>
<a href='#' style={{ color: '#95d5b2' }}>dWare.sk</a>
</div>
</div>
)
}
</Spring>
)
} else {
return (
<div className='upperDivLogoText' onMouseEnter={handleMouseEnter} onMouseLeave={handleMouseLeave}>
<span><a href='#' style={{ color: '#d8f3dc' }} >dWare.sk</a></span>
<a href='#' style={{ color: '#95d5b2' }}>dWare.sk</a>
</div>
)
}
}
render() {
return (
<div className='upperDiv'>
<this.LogoText
isMouseOver={this.state.isMouseOver}
handleMouseEnter={this.handleMouseEnter}
handleMouseLeave={this.handleMouseLeave}
/>
<div className='lowerDiv'>
<ul className='lowerDivMenu'>
<li><a href='#'>O MNE</a></li>
<li><a href='#'>MOJE PORTFÓLIO</a></li>
<li><a href='#'>KONTAKT</a></li>
</ul>
</div>
</div>
)
}
}
But if I hover over upperDivLogoText it just doesn't do anything. Any suggestions on how to fix this?
SOLUTION:
It is because of Spring version 9. For anyone having such a problem just uninstall latest spring and do npm i react-spring#8.0.20
It could be that onMouseLeave is being triggered on the first div just after onMouseEnter because it is unmounted, hence causing it to appear as if nothing is happening?
Wouldn't you just want onMouseEnter on the first one and onMouseLeave only on the second rather than both on each?
As on March-2021, and as mentioned in comments under this answer, react-spring V9 isn't yet released and may have breaking changed. Hence, It would be safe to use V8.
But, in V9, the animation is working using useSpring hook and animated.div:
Example:
import { useSpring, animated } from 'react-spring' // Using hooks in V9
function LogoText({ isMouseOver, handleMouseEnter, handleMouseLeave }) {
const style = useSpring({
opacity: isMouseOver ? 1 : 0,
from: { opacity: 0 },
})
if (!isMouseOver) {
return (
<div
className="upperDivLogoText" onMouseEnter={handleMouseEnter}
>
<span>
<a href="#" style={{ color: '#d8f3dc' }}>
dWare.sk
</a>
</span>
<a href="#" style={{ color: '#95d5b2' }}>
dWare.sk
</a>
</div>
)
}
return (
<animated.div style={style}>
<div
className="upperDivLogoText" onMouseLeave={handleMouseLeave}
>
<span>
<a href="#" style={{ color: '#d8f3dc' }}>
dWare.sk
</a>
</span>
<a href="#" style={{ color: '#95d5b2' }}>
dWare.sk
</a>
</div>
</animated.div>
)
}

First modal on each page not displaying data

I am making a workstation assessment website.
I am stuck with an issue I am having.
The modal is my a grandchild component (modal complete questions). I then have a component named questions as a parent and as the parent to that I have Admin Workstations.
Hierachy
1.AdminWorkstations,
2.Questions,
3.Modal,
(this is not full functionality of these components but is just for the use case I am asking for).
1.Parent gets WSAId(just a id).Passes down to questions.
2.Questions passes the modal component this.
3.Modal gets questions using this id.
However the first modal does not display.I have paginated the results of these page if this makes any diffrence.
this is my modal
import "./ViewWorkstationModal.css";
import React, { useState, useEffect } from "react";
import { Modal, DropdownButton, Dropdown } from "react-bootstrap";
function ModalCompletedQuestions(props) {
const [show, setShowState] = useState(0);
const [loadingToken, setLoadingToken] = useState(0);
const [answeredQuestions, setAnsweredQuestions] = useState([{}]);
useEffect(() => {
setLoadingToken(true);
let data = {
WSAId: props.WSAId
};
fetch("/get-completed-questions", {
method: "POST",
headers: {
Accept: "application/json",
"Content-Type": "application/json"
},
body: JSON.stringify(data)
})
.then(recordset => recordset.json())
.then(results => {
setAnsweredQuestions(results.recordset);
});
}, []);
function handleClose() {
setShowState(false);
}
function handleShow() {
setShowState(true);
}
return (
<>
<>
<div className="header-container">
<button
className="btn btn-primary"
style={{ float: "right" }}
onClick={handleShow}
>
Response Overview
</button>
</div>
<div>
<Modal
size="lg"
style={{ width: "100%" }}
show={show}
onHide={handleClose}
animation={true}
>
<h3 style={{ textAlign: "center" }}>{props.workStation}</h3>
{answeredQuestions &&
answeredQuestions.map(function(question, index) {
if (
question.QuestionResponse === "Y" ||
question.QuestionResponse === "N"
) {
return (
<>
<div
style={{
backgroundColor: "#E6E6E6",
padding: "1px"
}}
>
<ul>
{" "}
<b> Q :</b>
<div style={{ float: "right" }}>✔️</div>
{question.QuestionWhenAnswered}
</ul>
</div>
</>
);
} else if (question.QuestionResponse === "P") {
return (
<>
<div
style={{
backgroundColor: "#BDBDBD",
padding: "1px"
}}
>
<ul>
<b> Q :</b>
{question.QuestionWhenAnswered}{" "}
<div style={{ float: "right" }}>❌</div>
{/* <br />
<b> S :</b>
{question.SuggestedSoloution} */}
</ul>
</div>
</>
);
}
})}
</Modal>
</div>
</>
</>
);
}
this is my questions component
class Questions extends React.Component {
constructor(props) {
super(props);
console.log(props);
this.state = {
...props,
questionsAccepted: [],
questionsAcceptedCounter: "",
selectedSet: [],
ViewActivityToken: false,
noteToBeAdded: "",
notesFromDB: [],
addNoteToken: false,
answeredQuestions: []
};
}
render() {
if (!this.state.ViewActivity) {
if (!this.state.viewDetails && !this.state.ViewActivityToken) {
console.log(moment.locale());
return (
<div>
<ModalCompletedQuestions
RUId={this.props.RUId}
workStation={this.props.workStation}
WSAId={this.props.WSAId}
/>
<Link
to={{
pathname: "/admin-view-full-user-wsa-responses",
state: {
WSAId: this.props.WSAId
}
}}
>
<button style={{ float: "right" }} className="btn btn-primary">
View Full Details
</button>
</Link>
<br />
<li>
<b>User Id: </b>
{this.props.RUId}
</li>
<li>
<b>Workstation: </b>
{this.props.workStation}
</li>
<li>
<b>Date: </b>
{moment(this.props.date).format("L")}
</li>
<li>
<b>Complete Token: </b>
{this.props.completeToken}
</li>
</div>
);
} else if (this.state.viewDetails && !this.state.ViewActivityToken) {
return (
<div>
<button
style={{ float: "right" }}
onClick={e =>
this.setState({
ViewActivity: false,
viewDetails: false,
ViewActivityToken: false,
addNoteToken: false
})
}
className="btn btn-secondary"
>
Revert
</button>
<br />
<br />
{this.state.selectedSet &&
this.state.selectedSet.map((item, index) => {
return (
<div>
<li>
{" "}
<b>{item.QuestionWhenAnswered}</b>{" "}
</li>
<li>{item.QuestionResponse}</li>
<li>{item.Accepted}</li>
</div>
);
})}
</div>
);
}
} else if (this.state.ViewActivity && !this.state.addNoteToken) {
return (
<>
<button
style={{ float: "right" }}
onClick={e =>
this.setState({
ViewActivity: false,
viewDetails: false,
ViewActivityToken: false,
addNoteToken: false
})
}
className="btn btn-secondary"
>
Revert
</button>
<br />
<li>
<b>User Id: </b>
{this.props.RUId}
</li>
<li>
<b>Workstation: </b>
{this.props.workStation}
</li>
<li>
<b>Date: </b>
{moment(this.props.date).format("DD/MM/YYYY")}
</li>
<li>
<b>Complete Token: </b>
{this.props.completeToken}
</li>
{this.state.notesFromDB &&
this.state.notesFromDB.map((item, index) => {
return (
<div
style={{
backgroundColor: "white",
border: "inset",
borderWidth: "0.2px"
}}
>
<div style={{ float: "right" }}>
{moment(item.CreationTime).format("HH:MM DD/MM/YYYY ")}
</div>
<div>
<b>{`${item.UserStatus} `}</b>
</div>
<div style={{ textAlign: "left" }}>{item.Notes}</div>
</div>
);
})}
<br />
<button
onClick={this.AddNoteBtn}
className="btn btn-primary"
style={{ width: "100%" }}
>
Add Note
</button>
</>
);
}
}
}
How come when the first is clicked the modal appears blank but the rest of the modals are filled with the right data.
Essentially it seems as if though the first modal is not performing the data fetch which is within the modal component.
Any extra information needed let me know but these seem to be the most important for this use case.
Any help is much appreciated.
I completed this by using a condition within the use effect.
useEffect(() => {
setLoadingToken(true);
let data = {
WSAId: props.WSAId
};
fetch("/get-completed-questions", {
method: "POST",
headers: {
Accept: "application/json",
"Content-Type": "application/json"
},
body: JSON.stringify(data)
})
.then(recordset => recordset.json())
.then(results => {
setAnsweredQuestions(results.recordset);
});
}, [PUT YOUR CONDTION HERE]);
I simply just passed my props through so it says every time there is a new props do this.

onClick event never fires in React Child

I have a React-Redux application and I'm having issues launching a function on component click. When the logout button is clicked, it should trigger onClick={this.handleLogout}. However, Redux dev tools and adding a console log in the handleLogout prove that the function never executes.
Here are the two components, a standard navigation bar and a custom button component. I've left out some imports to shorten the code.
Navigation Bar
class Navigation extends React.Component {
handleLogout = () => {
this.props.logOut();
this.props.history.push("/login");
}
render() {
return (
<nav>
<span className="nav-left">
<Link className="light" to="/">
Home
</Link>
</span>
<span className="nav-right">
{this.props.authenticated ? (
<>
<Button to="/account">Account</Button>
<Button onClick={this.handleLogout} buttonStyle="danger">
Log Out
</Button>
</>
) : (
<Button to="/login">Login</Button>
)}
</span>
</nav>
);
}
}
Navigation.propTypes = {
authenticated: PropTypes.bool.isRequired,
logOut: PropTypes.func.isRequired
};
export default withRouter(Navigation);
Button
export default class Button extends Component {
state = {
classList: classNames({
button: true,
button_accent: this.props.buttonStyle === "accent",
button_danger: this.props.buttonStyle === "danger"
})
};
render() {
return (
<div className="button_container">
<div
className={classNames({
button_wrapper: true,
center: !this.props.left && !this.props.right,
left: this.props.left,
right: this.props.right
})}
>
{
this.props.to ? (
this.props.regular ? (
<a href={this.props.to} className={this.state.classList}>
{this.props.children}
</a>
) : (
<Link to={this.props.to} className={this.state.classList}>
{this.props.children}
</Link>
)
) : (
<span className={this.state.classList}>
{this.props.children}
</span>
)
}
</div>
</div>
);
}
}
Component Dev Tools
component dev tools
You forgot to pass onClick to the span that represents a button without a link
export default class Button extends Component {
state = {
classList: classNames({
button: true,
button_accent: this.props.buttonStyle === "accent",
button_danger: this.props.buttonStyle === "danger"
})
};
render() {
return (
<div className="button_container">
<div
className={classNames({
button_wrapper: true,
center: !this.props.left && !this.props.right,
left: this.props.left,
right: this.props.right
})}
>
{
this.props.to ? (
this.props.regular ? (
<a href={this.props.to} className={this.state.classList}>
{this.props.children}
</a>
) : (
<Link to={this.props.to} className={this.state.classList}>
{this.props.children}
</Link>
)
) : (
<span onClick={this.props.onClick} className={this.state.classList}>
{this.props.children}
</span>
)
}
</div>
</div>
);
}
}

pass value of clicked list to EditForm to edit

I am doing reactjs and redux for developing dashboard. I have done add, delete but editing is not working. When user clicks on item, the textfield should display with its current value and able to submit the changes. I can show textfield when clicked but could not show the current value of that item which is clicked. To display textField i have to use onClick on the li tag otherwise i could pass data like using this.props.editTab(tab). How can i now send data of clicked item to editTab action ?
constructor(props) {
super(props);
this.state = { open: false, editing: false };
}
editTab() {
const tabs = _.map(this.props.tabs, (tab) => {
if (tab.editable) {
return (
<li
className="list-group-items delete-tab-list"
onClick={() => this.setState({ editing: true })}
key={tab.id}
>
<i className="material-icons">{tab.icon}</i>{tab.name}
</li>
);
}
});
return (
<div className="device-action">
<Dialog
title="Update a Tab"
modal={false}
bodyStyle={{ background: '#fff' }}
contentStyle={customContentStyle}
actionsContainerStyle={{ background: '#fff' }}
titleStyle={{ background: '#fff', color: '#1ab394' }}
open={this.props.createTab.open}
onRequestClose={this.props.closeTabIcon}
>
<ul className="list-group">
{ this.state.editing ?
<EditForm
tab={this.props.tabs}
editing={this.state.editing}
/> :
tabs
}
</ul>
</Dialog>
</div>
);
}
handleEditSave = (name, icon) => {
this.props.editTab(name, icon);
}
render() {
return (
<div>
<form onSubmit={this.handleEditSave}>
<div className="tab-name">
<TextField
floatingLabelText="Name"
onChange={(name) => { this.setState({ name: name.target.value }); }}
/>
</div>
<div className="icon">
<AutoComplete
floatingLabelText="select any icon"
filter={AutoComplete.noFilter}
openOnFocus
onNewRequest={(e) => { this.setState({ icon: e.id }); }}
/>
</div>
<button className="btn">Save</button>
</form>
</div>
);
}
How can i pass clicked item data to EditForm component so i can trigger my action in this.props.editTab(tab) this way ?
You can simply track the tab you editing by saving it on the state.
This will work only if you want to edit 1 tab at time. otherwise you can use Object/Array.
constructor(props) {
super(props);
this.state = { open: false, editing: null };
}
editTab() {
const tabs = _.map(this.props.tabs, (tab) => {
if (tab.editable) {
return (
<li
className="list-group-items delete-tab-list"
onClick={() => this.setState({ editing: tab })}
key={tab.id}
>
<i className="material-icons">{tab.icon}</i>{tab.name}
</li>
);
}
});
const { editing } = this.state;
// editing is the Tab object that we edit
if (editing)
console.log("Editing tab: " + editable.name);
return (
<div className="device-action">
<Dialog
title="Update a Tab"
modal={false}
bodyStyle={{ background: '#fff' }}
contentStyle={customContentStyle}
actionsContainerStyle={{ background: '#fff' }}
titleStyle={{ background: '#fff', color: '#1ab394' }}
open={this.props.createTab.open}
onRequestClose={this.props.closeTabIcon}
>
<ul className="list-group">
{ this.state.editing ?
<EditForm
tab={this.props.tabs}
editing={this.state.editing}
/> :
tabs
}
</ul>
</Dialog>
</div>
);
}
handleEditSave = (name, icon) => {
this.props.editTab(name, icon);
}
render() {
return (
<div>
<form onSubmit={this.handleEditSave}>
<div className="tab-name">
<TextField
floatingLabelText="Name"
onChange={(name) => { this.setState({ name: name.target.value }); }}
/>
</div>
<div className="icon">
<AutoComplete
floatingLabelText="select any icon"
filter={AutoComplete.noFilter}
openOnFocus
onNewRequest={(e) => { this.setState({ icon: e.id }); }}
/>
</div>
<button className="btn">Save</button>
</form>
</div>
);
}

Categories

Resources