How to get value of data custom-attribute in JSX / React - reactjs

Let's say I create a data-custom attribute in JSX element to save some meta-data about that element.
Like:
return (
<button data-customData="red" onClick={(ev) => { console.log(ev.target.customData)}}>Teste</button>
)
If I try to acess the data-custom attribute like you see in the code I will get undefined.
But If I try something like ev.target.style or ev.target.id I will not get undefined.
What is the difference and how can we acess this value ?

you're not calling the right value, you are calling a property called customData but the attribute name is data-customData, and in order to get the value you need to change how you call the attribute using the getAttribute function that the element (ev.target) provides
return (
<button
data-customData="red"
onClick={(ev) => {
const element = ev.target;
console.log(element.getAttribute("data-customData"));
}}
>
Click Me
</button>
)
The thing you're trying to is not a very common pattern and if you want to get a value from the user you should use the right control (input, radio, select) instead of using a data attribute.

Related

How would I change the component props onClick with a functional component?

I am trying to change the value of the prop onClick. Basically the model is set up to show only one input bar if the enum is set to one and vise versa for two. How would I switch the value of the prop with an onClick function? Below is what I have tried to this point. Right now I am getting the following error: "Argument of type 'boolean' is not assignable to parameter of type 'SetStateAction<Enum_Search_Inputs | null | undefined>'"
const [pickInput, setPickInput] = useState(search.inputs)
<Breadcrumb
borderBottom={'1px'}
borderColor={'white'}
color={'white'}
separator=""
>
<BreadcrumbItem>
<Button color={'white'} variant='link' onClick={() => setPickInput(pickInput === 'two')}>Search by location</Button>
</BreadcrumbItem>
<BreadcrumbItem>
<Button color={'white'} variant='link' onClick={() => setPickInput(pickInput === 'one')} >Search by keyword</Button>
</BreadcrumbItem>
</Breadcrumb>
You should add boolean type when you declare pickInput
const [pickInput, setPickInput] = useState<Enum_Search_Inputs | null | undefined | boolean>(search.inputs)
It looks like you're trying to set the state as a boolean instead of as a one or a two. Your function should look like the one below if you're trying to set the state to be the word "one" or "two", though I'd definitely recommend using an integer for that.
() => setPickInput("one")}
() => setPickInput("two")}
Right now, you're actually doing a comparison inside the function where you set your state (pickInput === 'one') which is going to return a boolean to your setPickInput function based on whether your variable pickInput's value is 'one' instead of actually setting a value inside it.
React Docs link to hooks and state
JS Comparisons documentation
I was able to solve this by setting up a function that used state to set the value on click.
function searchLocationHandler() {
setPickInput('two')
search.inputs = 'two'
}
function searchKeywordHandler() {
setPickInput('one')
search.inputs = 'one'
}

React dynamic add select input field

I am trying Create a select field dynamically. When clicking the add button, it will dynamically add select fields. I have and issue where the values don't change.
My code can be viewed on codesandbox:
https://codesandbox.io/s/react-select-field-dynamically-uo4dy?file=/src/App.js
Take a look at my changes:
Forked sandbox
// I added a 3rd argument for the name:
const handleRoomChange = (option, index, name) => {
const value = option.value; // you had this as 'const { value } = option.value' which dereferences value twice
console.log(value);
const list = [...roomInputs];
list[index][name] = value; //you had this as list[index][value]
setRoomInputs(list);
};
// onChange passes the name as 3rd argument to handleRoomChange
<Select
name="boardBasic"
placeHolder="Board"
value={options.value}
onChange={option => handleRoomChange(option, i, "boardBasic")}
options={options}
styles={{
menu: (provided) => ({ ...provided, zIndex: 9999 })
}}
/>
You have three problems that I can see.
First, you only have a handleRoomChange function that is trying to handle both room changes and board changes. You should probably have a handleBoardChange function, as well.
Second, if you output option to the console inside handleRoomChange, you will notice that option.value is a number. So, when you proceed to set list[index][value] to value, what you're saying is that you want (for example) roomInputs[1][1] to be 1. roomInputs[1] has no 1 property, which is why you will end up with the wrong properties inside your object on submission. You need to be setting roomInputs[1].roomType to value, instead (and the boardBasic property in your handleBoardChange method, when you write it).
Third, you are trying to use object destructuring to assign object.value to your value variable...but you're trying to destructure object.value instead of destructuring object. For this reason, value is undefined every time you run the function. Replace the assignment with const { value } = option; and you will start getting defined values back.

How to get a reference to a DOM element that depends on an input parameter?

Say I have the standard TODO app, and want a ref to the last item in the list. I might have something like:
const TODO = ({items}) => {
const lastItemRef = Reeact.useRef()
return {
<>
{items.map(item => <Item ref={item == items.last() ? lastItemRef : undefined} />)}
<>
}
}
But this doesn't seem to work - after lastItemRef is initialized, it is never subsequently updated as items are added to items. Is there a clean way of doing this without using a selector?
I think in your case it depends upon how the items list is updated. This is because useRef won't re-render the component if you change its current attribute (persistent). But it does re-render when you choose, for example, useState.
Just as a working case, see if this is what you were looking for.
Ps: check the console

React onClick target.value undefined

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.

I want to map over an array using React which in turn contains an object

I have an array which is structured as follows. I got this array from a postgresql db as:
[{"pp_all":"{"pp_ident":43,"pp_titel":"abc","pp_beschreibung":null}]
I use REACT to map over this array.
{gesamt.map((elemt, index) => (
<>
<h5 key={index}>{elemt.pp_all}</h5>
</>
))}
As a result I get the following to see in my browser:
{"pp_ident":43,"pp_titel":"abc","pp_beschreibung":null}
How do I get the value of the individual attributes?
EDIT
If i hover over the result data.pp_all i got the follwowing :
"{"pp_ident":43,"pp_titel":"abc","pp_beschreibung":null}"
So i think it is the wrong format in the frontend.
But how can it be, because if i print it out, i can see the above
And if i trie to do the following:
{gesamt.map((data) => {
console.log(data.pp_all.pp_titel);
})}
I got an undefined error
You need to target individual attribute with another dot. Like the following
{elemt.pp_all.pp_indent}
{elemt.pp.all.pp_titel} and so on..
Because you got the object so it works same like you would target and object's property
The answers absove will show you how to access the individual fields, but if you want to display all values the way you presented your html, you could loop over the keys of that object and return the value like this:
{gesamt.map((elemt, index) => (
<>
<h5 key={index}>{Object.keys(elemt.pp_all).map(key => elemt.pp_all[key])}</h5>
</>
))}
you need to iterate over each object to get attribute value
gesamt.map(data => {
for (let key in data ) {
<h5>{data[key].pp_titel}</h5>
<h4>{data[key].pp_ident}</h4>
}
})

Resources