React onClick target.value undefined - reactjs

I'm using Antd to generate Tags and I want to modify state using onClick event.
My parent Component (Where I generate a List of Items)
onRiskClick(e) {
e.preventDefault();
console.log(e.target);
console.log(e.target.value);
}
[...]
render() {
return (
[...]
<div className="square risk_orange">
<RenderingRiskMatrix
risks={this.state.risks}
impact="2"
likelihood="5"
color="red"
onRiskClick={this.onRiskClick} <-- passing onRiskClick function as props
></RenderingRiskMatrix>
</div>
My Child Function RenderingRiskMatrix
<Tooltip key={risk.id} title={risk.name}>
<Tag
key={risk.id}
color={props.color}
onClick={(event) => props.onRiskClick(event)}
>
{risk.id}
</Tag>
</Tooltip>
What I got in console :
<span class="ant-tag ant-tag-red" ant-click-animating-without-extra-node="false">R028</span>
undefined
which means e.target exists and not e.target.value which should be R028 no ?
Thanks,

I think there is a simpler way to accomplish your goal. The value you want is a child, not the value. You already have access to the value you want though, so I would use it like this:
<Tooltip key={risk.id} title={risk.name}>
<Tag
key={risk.id}
color={props.color}
onClick={() => props.onRiskClick(risk.id)}
>
{risk.id}
</Tag>
</Tooltip>
Then use it like this:
onRiskClick(value) {
console.log(value);
}
This will be a more flexible solution than accessing the innerHTML from the event target. You can now display it any way you want (or even render another component), and you function will still get the value it needs.

In this case, you already have the element, then to get the content inside the element you need to use e.target.innerHTML to get the tag content, other way is using e.target.textContent but is not supported on Firefox.

you should call e.persist() before console.log
If you want to access the event properties in an asynchronous way, you should call event.persist() on the event, which will remove the synthetic event from the pool and allow references to the event to be retained by user code.

Change your onclick function like this.you need to pass the event data to the function and use the data
const onRiskClick = e =>{
function ....
}
.....
<RenderingRiskMatrix
risks={this.state.risks}
impact="2"
likelihood="5"
color="red"
onRiskClick={e=>{
onRiskClick(e)
} <-- passing onRiskClick function as props
></RenderingRiskMatrix>

I found a solved issue about the "undefined" value from e.target.value
here
https://github.com/facebook/react/issues/4745
the solution was to use e.currentTarget.value instead
HTH.

Related

Simulate click event in React with TypeScript material-ui

I'm rendering some material-ui TextFields. By manually typing the value inside it, it'll work properly. It is using handleChange() (change) and handleBlur() (autosave) to handle those events. but the scenario is I have to update the value not by manually typing but from the store.
So, if I pass the value from the store, it is not actually updating the value unless I click inside the field and click away or tab out. the value is showing inside the field but not invoking handleChange() and handleBlur() which are the only way to update the value inside. Also I have to type at least a value.
Approach:
I set an onFocus to the field and on it's handleFocus, I'm trying to either simulating click() and blur() or calling handleClick() and handleBlur(). If I simulate a click event,
Uncaught TypeError: element.click is not a function
If I try to call handleChange() and handleBlur()
readonly refO: React.RefObject<HTMLInputElement>;
constructor(props: InputProps) {
super(props);
this.refO = React.createRef<HTMLInputElement>();
}
...
<TextField
autoFocus
inputRef={this.refO}
id={this.labelId}
required={required}
label={label}
error={error}
value={this.setValue()}
onBlur={handleBlur}
onChange={handleChange}
disabled={disabled}
fullWidth
type={type}
InputLabelProps={InputLabelProps}
InputProps={{ className: cx({ [classes.modified]: isModified }) }}
onFocus={this.handleFocus}
/>
What can I do inside handleFocus() in order to achieve this. or the proper approach to achieve this. I'm very new to TypeScript. is my approach wrong or any other way to overcome this.
handleFocus = (element: HTMLInputElement) => {
element.click();
this.props.handleChange();
this.props.handleBlur();
}
PS: cannot add more code due to some sensitivity issues.
solved the issue.
i knew it has to be done from inside the handleFocus. but what i was doing call other event handlers from it. then i thought why should i. the function has been invoked so just update the values from it.
handleFocus = (value) => {
// update my value
}
it's unconventional but all we require is the result.
ps: i even pinged few people on twitter(this has put our reputation on the stake. it was a race against time). i was that desperate. i apolagize to them.

Launch keyboard event from React ref

I have a React component that has an input element with an attached ref. I am aware of the common: inputRef.current.focus(); usage of a ref to focus a text input. But, I am struggling to find a good solution to dispatch a certain keyboard event from inputRef.current. I have tried:
let downEv = new KeyboardEvent('keydown', {'keyCode': 40, 'which': 40});
inputRef.current.dispatchEvent(downEv);
But, that doesn't seem to do anything.
KeyboardEvent is a native browser event (which is different than React's Synthetic event) hence you need to add a native listener as well like below in order to listen to them. example on csb
useEffect(()=>{
ref.current.addEventListener('keydown',handleKeyDown)
},[ref])
It's possible to do this, and not need to use ref.
You can try isolating what you want to trigger by doing this:
handleKeyPress = (e) => {
if (e.keyCode === 40) {
// Whatever you want to trigger
console.log(e.target.value)
}
}
<input onKeyPress={handleKeyPress} />
You can also trigger this from a form if you prefer:
<form onKeyPress={handleKeyPress}>
...
</form>

Set the on click method conditionaly in a component

I have a component with an onClick method, where I would like to set the method conditionaly based on the property I get in the component. This is how to code looks like:
<Image
className={styles.editIcon}
src={openForm ? editPeriodDisabled : editPeriod}
onClick={() => toggleFormCallback(id)}
alt="Rediger periode"
/>
I have a boolean property openForm, by which I would like to set the method in the onClick property of the Image component. So, something like this for example:
openForm ? null : toggleFormCallback(id)
But, not sure how to do that with an arrow function?
You can use bind():
onClick={openForm : null ? toggleFormCallback.bind(this, id)}
bind() returns a new function which is the same as the original but bound to the given context. You can also bind some or all of the parameters.
The easiest solution.
<Image
className={styles.editIcon}
src={openForm ? editPeriodDisabled : editPeriod}
onClick={() => { if (openForm) { toggleFormCallback(id) } }}
alt="Rediger periode"
/>

How can I pass multiple props in a single event handler in ReactJS?

I'm trying to add a onClick listener to a li and the props will be passed to another component that will eventually call a function. My first thought was simply put 2 onClick, but I got a warning for duplicate props.
<li onClick={props.headlinesClicked} onClick={props.getData}>Top Headlines</li>
Then I tried the vahnilla JS way but I assume it's not working because these are expressions rather than actual functions.
<li onClick={() => {{props.headlinesClicked}; {props.getData}}}>Top Headlines</li>
How can I pass these multiple props in a single onClick?
Your first snippet won't work as you can't bind to a prop multiple times. The second is incorrect firstly because anything inside the brackets is JS, so the additional brackets inside are unnecessary and you're also not invoking any of the functions.
Think of it this way, onClick={props.headlinesClicked} is kind of like a shorthand for onClick={() => props.headlinesClicked()} (not exactly as onClick also passes an event as the first parameter, but hopefully you get the gist of it). So, when you do onClick={() => props.headlinesClicked} you're not actually calling the function, just returning a reference to it which then doesn't actually do anything.
You could either do onClick={() => props.headlinesClicked(); props.getData()}, or extract it to a new function/method that does both calls, then invoke it with onClick={myNewMethod} or onClick={() => myNewMethod()}.
Have the passed function call the other two functions normally:
<li onClick={() => { props.headlinesClicked(); props.getData() }}>Top Headlines</li>
Alternatively (recommended for readability), make a new function which calls those two functions. Consider making the function a class method if it's a class component.
const handleListItemClick = () => {
props.headlinesClicked()
props.getData()
}
return <li onClick={handleListItemClick}>Top Headlines</li>
I have recommended below way it will work 100%
const handleListItemClick = () => {
if(props.headlinesClicked){
props.headlinesClicked()
}else{ props.getData() }
return <li onClick={handleListItemClick}>Top Headlines</li>
Note:react have confuse two props we mentioned same onClick .

Is render method of a component run in react-virtualized rowRenderer

I am using a List provided by react-virtualized. Inside the rowRenderer I return a more complex component. This component has some events defined for it. When an event is triggered, a part of the this component should be updated with new structure, e.g. a new input is rendered inside the row. This doesn't not seem to work when used inside the List.
<List height={height} width={1800} rowCount={this.state.leads.length} rowHeight={rowHeight} rowRenderer={this.rowRenderer} />
Here's the rowRenderer:
rowRenderer(props) {
let opacityvalue = 1
if (this.state.deleted.indexOf(props.index) >= 0) {
opacityvalue = 0.3
}
return (
<LeadItem {...props}
lead={this.state.leads[props.index]}
leadKey={props.index}
...
/>
)}
Here's the element that should show up when a specific event is triggered:
{self.props.lead.show ? <Selectize
queryfield={'tags'}
handleChange={(e) => this.props.updateLeadData(self.props.leadKey, 'tags', 'update', e)}
value={self.props.lead.tags}
create={false}
persist="false"
multiple
options={self.props.TAGS}
/> : <div>{taglist}</div>}
EDIT: Here's a simple example where I prove my point.
https://codesandbox.io/s/2o6v4my7pr
When user presses on the button, there must appear a new element inside the row.
UPDATE:
I see now that it's related to this:
https://github.com/bvaughn/react-virtualized#pure-components
I think you can achieve what you're trying to do by passing through this property to List as mentioned in the docs:
<List
{...otherListProps}
displayDiv={this.state.displayDiv}
/>

Resources