I am using Material Table in Reactjs to show the table Data. Here I am stuck at a part where I want to change state when I click on the edit option/icon. I do not want to change the onClick functionality of Edit button, but I just want to access edit icon. Is there any way I can achieve it?
Note: I only want it when I click on the edit(pen) icon before it becomes the OK and Cancel buttons.
First of all you have to remove the default edit button. Then use a Button in action and tableRef props. Now, all you have to do is put the edit's code in onClick event like this:
var _interopRequireDefault = require("#babel/runtime/helpers/interopRequireDefault");
var _objectSpread2 = _interopRequireDefault(
require("#babel/runtime/helpers/objectSpread")
);
...
export default function MaterialTableDemo() {
const tableRef = useRef(null);
...
return (
<MaterialTable
...
tableRef={tableRef}
actions={[
{
onClick: (event, rowData) => {
console.log("Clicked", rowData);
tableRef.current.dataManager.changeRowEditing(rowData, "update");
tableRef.current.setState(
(0, _objectSpread2["default"])(
{},
tableRef.current.dataManager.getRenderState(),
{
showAddRow: false,
}
)
);
},
},
]}
...
/>
)
}
This part is the requirements that material-table uses in it's code:
var _interopRequireDefault = require("#babel/runtime/helpers/interopRequireDefault");
var _objectSpread2 = _interopRequireDefault(
require("#babel/runtime/helpers/objectSpread")
);
In addition this is the code that you need to fire edit action:
tableRef.current.dataManager.changeRowEditing(rowData, "update");
tableRef.current.setState(
(0, _objectSpread2["default"])(
{},
tableRef.current.dataManager.getRenderState(),
{
showAddRow: false,
}
)
If this html template is written by you then you can wrap icon in some parent element and add click event on parent.
Related
TL/DR: My simple toggle function fires twice when button is clicked.
I'm using useEffect in a React (w/ Next.js) component so that I can target the :root <html> tag for which I need the class to be toggled. The code is the following:
useEffect(() => {
const toggleMode = () => {
const root = document.documentElement;
root.classList.toggle("dark");
console.log("click");
};
const toggleBtn = document.querySelector("#toggle-btn");
toggleBtn.addEventListener("click", toggleMode);
I have the necessary imports, the code is placed inside the main component function before the return, and there's no errors in the console at all.
The only issue is that the function is fired twice every time the button is clicked and I cannot find any reason why or solutions online.
Would really appreciate your help and please let me know if I'm missing any information.
Cheers!
Your problem is coming from registering the event listener in a non-react way.
By registering the listener via
const toggleBtn = document.querySelector("#toggle-btn");
toggleBtn.addEventListener("click", toggleMode);
you are setting up a new listener each time the function is run, even if the DOM is not updated. This could result in multiple listeners being registered and firing simultaneously.
You need to add your listener the react way.
function Component ( props ){
const [ isFirst, setIsFirst ] = useState( true );
const [ toggle, setToggle ] = useState( false );
useEffect(() => {
if( isFirst ) {
setIsFirst( false );
return;
}
document.documentElement.classList.toggle("dark");
}, [ toggle ] );
return <div>
<button id="toggle-btn" onClick = { e => setToggle( !toggle ) } />
</div>
}
I resolved a similar problem in this post: Why does my NextJS Code run multiple times, and how can this be avoided?
Your code should only run once if you disable react strict mode.
const NavigationButtons = ({onBtnClicked, btnClass, label, route, btnAct}) => {
return (
<p
className={`btn ${btnClass} ${btnAct}`}
onClick={() => onBtnClicked(route)}>
{label}
</p>
);
};
This is my button component, I'm giving it to another component as btns1 props
{!isSigned?btns1:windowPixel?btns1:null}
Basically, when isSigned is false, btns1 is rendered. There's really no problem here. When isSigned is true, it checks if windowPixel is true, this is changed to true by App.js as a state by measuring the current window. It works perfectly unless I click the button. Resize the window where windowPixel will be false, then on my first click, it doesn't trigger onClick. After that onClick works again.
componentDidMount() {
if (window.matchMedia(`(max-width: 990px)`).matches) {
this.resizeWindow(true);
}
window.addEventListener("resize", () => this.resizeWindow(window.matchMedia(`(max-width: 990px)`).matches));
}
This is what checks the window size for windowPixel. chatScroll, is for the panel that expands when btn1 is clicked, btnAct is just for a css that change the color of the button while the panel is expanded. For now, I've put click(), like a bandaid.
resizeWindow = (windowPixel) => {
const {chatScroll, btn1Act} = initialState;
if (windowPixel !== this.state.windowPixel) {
if (windowPixel === false) {
if (this.state.isSigned) {
document.getElementById('btn1').click();
this.setState({chatScroll, btn1Act});
}
}
this.setState({windowPixel});
}
};
The Reason Is Simple Brother in First Click Your Object or function or variable what ever it is , Just Initialize in first click and when you click second time it will Work as per your code.
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
I have a modal dialog that I want to close if the user clicks outside of the modal. I have written the following useEffect code but I run into following issue:
The modal dialog contains a number of children (React Nodes) and those children might change (e.g. the user deletes an entry of a list). Those interactions trigger my onClick method but as the clicked list item has been removed from the modal, the modal closes even though the click was within the modal.
I thought adding [ children ] at the second parameter for useEffect would cleanup the old effect event listener quick enough that the method does not run again but this is not the case.
I handled the same issue in a class component with a ignoreNextClick-state but there must be a cleaner solution, right?
useEffect( () => {
const onClick = ( event ) => {
const menu = document.getElementById( 'singleton-modal' );
if ( !menu ) return;
// do not close menu if user clicked inside
const targetInMenu = menu.contains( event.target );
const targetIsMenu = menu === event.target;
if ( targetInMenu || targetIsMenu ) return;
onCloseModal();
};
window.addEventListener( 'click', onClick, false );
return () => window.removeEventListener( 'click', onClick, false );
}, [ children ] );
I found a solution that does not require any sort of storing old props.
The useEffect call looks like this:
useEffect( () => {
const onClickOutside = () => onCloseModal();
window.addEventListener( 'click', onClickOutside, false );
return () => window.removeEventListener( 'click', onClickOutside );
}, [] );
Adding the following click listener to the modal directly will stop the window click-listener from being called if the user clicked inside the modal.
<div
className={`modal ${ classes }`}
onClick={event => event.stopPropagation()}
role="presentation"
>
{children}
</div>`
I also added the role presentation to make the modal more accessible and aria-conform.
You can check parent of modal from the event.target.
If the current target is within the modal then return.
You can use closest to do that.
See the following solution.
...
if (event.target.closest( '.singleton-modal' ) || event.target.classList.contains('singleton-modal')) {
return;
}
...
I'm trying to add a class to a div wrapping an input on focus with Redux and React.
My React component looks like this:
import React from 'react'
const Input = ({ value, onChange }) => (
<div className="">
<input type="email" onChange={onChange} value={value} />
</div>
)
export default Input
When a user focuses on the input, I want the class selected to be added to the div. The component is connected using react-redux.
The two ways I've tried so far:
Attempt 1
Add an onFocus listener to the input and dispatch an action that adds the inputs focus state into the inputs state , for example:
{
value: '',
focused: true
}
If focused is true, add the class with className={focused ? 'selected' : ''}
My concern with this approach is I could get into issues where multiple inputs have focused: true. So I'd have to manage that myself and look through the whole input state and reset to false before setting focus on a new input.
Atempt 2
Add an onFocus listener to the input and dispatch an action that contains the ID of the focused input and store the ID in the state. This would solve the issue of having to reset all other inputs to false.
My concern with this is I'd have to give every input I wanted this feature on a unique ID (this could possibly use Reacts ID). I'd have to add something like className={ID === focusedID ? 'selected' : '')
I feel like there must be a better way to achieve this. Any help would be appreciated.
Thanks
You dont even need Redux for that, just store the "selected" state in the component.
Something like this
var InputComp = React.createClass({
getInitialState: function() {
return {focus: false}
},
onFocus : function(){
this.setState({focus: true})
},
onBlur: function(){
this.setState({focus: false})
},
getClass: function(){
if(this.state.focus === true)
return "selected";
else
return "";
},
render: function() {
var inputClass = this.getClass();
return <div className={inputClass}><input onBlur={this.onBlur} onFocus={this.onFocus}/></div>
}
});
ReactDOM.render(
<InputComp/>,
document.getElementById('container')
);
jsfiddle
You need to use the :focus pseudo-selector. You need to add a class to your divs, for instance, focusable. If that is done, you need this CSS rule:
.focusable:focus {
/* Your rules for selected */
}