React conditional onClick with ampersand - javascript

I want to edit a card if allowed=true. I came up with this solution:
const editCard = (onEdit, id, allowed) => {
if (allowed) {
onEdit(id);
}
};
<Card onClick={() => editCard(onEdit, id, allowed)}>Card</Card>
I thought of making a simpler onClick like so:
<Card onClick={() => allowed && onEdit(id)}>Card</Card>
Can I make on onClick like so with the ampersand? If allowed=true then edit, otherwise onClick should not do anything.
It seems to work but I don't know if it will always work. Can this cause bugs and is there a better way to implement this click event?

Yes, it will work as expected :)
true && something() calls something function
false && something() returns just false while not calling something

Yes, that will work. But you may also use like:
<Card allowed onClick={() => onEdit(id)}>Card</Card>
Then check the allowed props.
Just using allowed is equivalent to allowed={true}. If the allowed option is false you want to send, you don't need to pass the props.
But in your case, it's dynamic. So, you can use like:
<Card allowed={allowed} onClick={() => onEdit(id)}>Card</Card>
So, depending on the case it will be either allowed={true} or allowed={false}.
And oh, you want to use it in editCard, so you may just use like:
<Card onClick={() => onEdit(id, allowed)}>Card</Card>
A good use case with conditional statement would be to use like: (only show card if allowed is true)
{
allowed &&
<Card onClick={() => onEdit(id)}>Card</Card>
}
This way, you're ensuring clear instruction with your code. So, you found sorts of ways. Happy coding!

Related

React-DnD: Using IsDropDisabled to disable dropping wrong element type

I've been trying to find an answer to this for a while now and the library, while being very nice and well done... lack very much in clear documentation. I'm hoping to partipate in improving it once I get a clear understanding of it.
Here's what I'm trying to accomplish.
I have a hierarchy of object that is quite complex and multiple draggable type can be mixed in the same level and some of these can even have childrens that are these same dragable.
That render the "type" property not working for me. I want to combine "IsDropDisabled" with "draggingOverWith" to make it happen instead and manage the complexity there.
Basically, the idea is that when the item I'm currently dragging is passing "over" a potential dropable, I want to check the type against an "allowed" array of type and allow it if the type is right.
For that, I want to access "snapshot.draggingOverWith" from the Droppable but the issue is... that "IsDropDisabled" is above in the code hierarchy so I'm kinda of lost as to how the code in the library actually does that comparison.
The idea would be something like that:
<Droppable droppableId={props.verticalgroup.id} isDropDisabled={() => {CompareTypes(snapshot.draggingOverWith, ['Type1', 'Type3'])}>
{(provided, snapshot) => (
<div
{...provided.droppableProps}
ref={provided.innerRef}
className={snapshot.isDraggingOver ? 'changeBackground' : ''}
>
...[Other Code]
</div>
)}
</Droppable>
Thanks for helping.
I think you could try to use the onDragStart method from the DragDropContext and send required information to Droppable for isDropDisabled to work conditionally.
Like they do here on their egghead course video.
const [isDropDisabled, setIsDropDisabled] = useState(false);
const onDragStart = (task) => {
setIsDropDisabled(task.something === 'xyz') // <= your condition goes here
}
and
<DragDropContext onDragStart={this.onDragStart} ...>
...
</DragDropContext>
lastly, in your Droppable use that as value
<Droppable droppableId={props.verticalgroup.id} isDropDisabled={isDropDisabled}>
{(provided, snapshot) => (
<div
{...provided.droppableProps}
ref={provided.innerRef}
className={snapshot.isDraggingOver ? 'changeBackground' : ''}
>
...[Other Code]
</div>
)}
</Droppable>

this."FunctionName" is not a function

I would like using a function in the render() who will be calling multiple time because it's call for each element of a Map(). But for some reasons my function is not recognized correctly, I get the error :
this.IsHeStillAlive is not a function
I totally rewrote my post to make it easier to understand and here is the link for my exemple on SandBox : https://codesandbox.io/s/test-uz-713xy.
in this exemple I try to use the functions "IsHeStillAlive" and "SwitchButton".
thanks for your help.
You can try with Ternary operator as the following:
<div className="slave">
<h3>{panel.price}€</h3><br/>
{
panel.name === 'Basique' ?
<Button className="buttonStore"
onClick={() => { this.UnsubcribeIt() }}>
Unsubscribe
</Button> :
<Button className="buttonStore"
onClick={() => { this.buyit(licenceName) }}>
Buy Now
</Button>
}
</div>
Or shorter in the first <Button /> as onClick={this.UnsubcribeIt}.
I think you should extract dataGet first so it wont have confusing this
render(){
let {dataGet} = this.state
return (
{this.state.dataGet.map(mapPanel)}
)
}
tell me if that is working
Someone outside this forum find me a solution.
The correction is in my sandbox link but if one day the lin is dead ...
just in case here are the step to correct my issue:
move your methods out of the class,make them a function components in the same file.
change the panel param to props . Inside props will be a panel prop
render the components like
it will not be very explicit if the sandbox link is dead but that will maybe help.

Why is this React method not working as expected?

I have some code that is meant to eliminate placeholders onFocus and return them onBlur, it seems to work properly for the login text input, but not for the password one. Do you mind having a look at the code?
This is the method in question:
togglePlaceholder = (nodeType:string,localStateValue:string) => {
switch (eval(`this.state.${localStateValue}`)) {
case nodeType:
return this.setState({[localStateValue]:null});
case null:
return this.setState({[localStateValue]:nodeType});
}
}
I'm using eval here because I'm planning to reuse this function across multiple components to toggle their local state.
These are the components:
<TextInput style={styles.logInFormInput}
placeholder={this.state.logInPlaceholder}
onFocus={()=>this.togglePlaceholder('login','logInPlaceholder')}
onBlur={()=>this.togglePlaceholder('login','logInPlaceholder')}
></TextInput>
<TextInput style={styles.logInFormInput}
secureTextEntry={true}
placeholder={this.state.passwordPlaceholder}
onFocus={()=>this.togglePlaceholder('password','passwordPlaceholder')}
onBlur={()=>this.togglePlaceholder('password','passwordPlaceholder')}
></TextInput>
Seems to be working properly for login, but not password.
Given that you are just hiding or showing I think you could use a pivot of thinking to solve this a little easier :)
The simplest way in my mind to would be to track the id of the currently focused element and use it to conditionally render the placeholder:
<TextInput onFocus={() => setActive(id)} onBlur={clearActive} placeholder={this.state.activeId === id ? 'placeholder' : ''} />
It would be simple to create a HoC which manages the inputs within, allowing you to group it accordingly

Fix a 'Cannot read property handleClick of undefined error' (and issues related to deleting an item from the DOM)

Background
I'm working on a final project for school that displays a list of tv shows/programs using cards. I am trying to set up a way to delete a card. I'm getting all sorts of turned around trying to get this delete to work on my frontend. I've spent so long researching the issue that every solution I think of now seems both right and wrong.
First, there was a problem where programId was undefined which I fixed. Now I can't figure out how make make my this in this.handleClick work. This solution made me think that I might need to use bind. But I am not sure.
Code
This is a section of my Program.js file, where the card is styled and props passed in to populate fields like name, network, and image. I use props.match.params because I've implemented React Router and need to access each card's data for the ternary statements inside. EDIT: Program.js is a functional component. I've included a link.
let handleClick = (id) => {
this.props.deleteProgram(id)
}
let program = props.program ? props.program : props.programs[props.match.params.id - 1]
let programId = program.id
return(
<Grid.Column>
<Card onClick={(_) => this.handleClick(programId)}>
<Image src={program ? program.image : null} wrapped ui={false} />
<Card.Content>
<Card.Header>{program ? program.name: null}</Card.Header>
<Card.Meta>
<span className='date'>{program ? program.network : null
</span>
</Card.Meta>
Here is my Programs.js file, which creates each Program component. I am unsure whether I should import my {deleteProgram} action/function in this file where I am creating each Program, or if I need to import it directly in Program.
EDIT: Programs.js is a functional component. I've added a link.
<Grid columns='six' divided='vertically'>
<Grid.Row >
{props.programs.map((program) => <Program key={program.id} program={program} />)}
</Grid.Row>
</Grid>
This is the programsReducer file with the case statement for deleting a program.
case 'DELETE_PROGRAM':
const programs = state.programs.filter(program => program.id !==
action.id)
return {programs}
Here is my deleteProgram action/function.
return (dispatch) => {
fetch(`http://localhost:3000/api/v1/programs/${id}`,{
method: 'DELETE',
headers: {'Content-Type': 'application/json'}
})
.then(res => res.json())
.then(res => dispatch({type: 'DELETE_PROGRAM', id: id}))
}
}
Recap of Questions
Do you know why I am getting an error that this in my this.handleSubmit is undefined?
Which file --Programs.js (with the .map) or Program.js (which each individual card -- should I import my {deleteProgram} function/action into?
Bonus Round
If memory serves, I need to put this onClick method on the entire card. I would love to call it on a delete button I made within the card. Can someone confirm whether this is correct or not?
Thank you very much for your time! :-)
Change your code to the following:
let handleClick = (id) => {
props.deleteProgram(id)
}
let program = props.program ? props.program : props.programs[props.match.params.id - 1]
let programId = program.id
return(
<Grid.Column>
<Card onClick={(_) => handleClick(programId)}>
<Image src={program ? program.image : null} wrapped ui={false} />
<Card.Content>
<Card.Header>{program ? program.name: null}</Card.Header>
<Card.Meta>
<span className='date'>{program ? program.network : null
</span>
</Card.Meta>
Question 1: One of the ways to bind this is in the constructor of the component.
this.function = this.function.bind(this);
Regarding Question 2: I would send the deleteCardFunction() in as a prop for each individual card. Then call it from the card with the id when you want to delete it.
Since this is a function component, not a class, you shouldn't use this there. Just use the function name.
<Card onClick={() => handleClick(programId)}>
should even work without binding it in there, since you are already doing it with an arrow function in the function declaration:
<Card onClick={handleClick(programId)}>
I would import delete into Program.js, since it makes sense to have the delete button inside that.
Another neat trick, instead of using the ? : shorthand, you can do it even shorter, using ||, like:
let program = props.program || props.programs[props.match.params.id - 1]
To be able to put another onClick inside the card, you will have to stop the event from bubbling up, calling event.stopPropagation() before or inside your delete method.

React getting the ID of clicked button

I have 5 clickable links, each with unique ID. I am trying to get the ID of the link that was clicked. I have tried two methods but neither work as I would like.
Inside render I have:
this.state.data.map((dynamicData, key) =>
<a href={"/#/template"} id={dynamicData.id} onClick={() => this.reply_click(this.id)}>{dynamicData.name}</a>
Edit</button>
Basic method that returns undefined. What am I doing wrong?:
reply_click(clicked_id) {
console.log(clicked_id);
}
Using an arrow function will maintain the context of this from the outside, which won't be the this you want. You could try to use a regular function (function () { }) instead, but I'm not sure if this will be what you want or not there either.
You can, however, definitely use e.target.id to get what you want:
onClick={e => this.reply_click(e.target.id)}
That said, you should really avoid creating functions inside of things as it can create significant performance issues. It's much better to just create a function and pass it in:
// somewhere above
const handleClick = e => this.reply_click(e.target.id);
// attribute
onClick={handleClick}
you can do this
<a href={"/#/template"} id={dynamicData.id} onClick={() => this.reply_click(dynamicData.id)}>{dynamicData.name}</a>
or another way
<a href={"/#/template"} id={dynamicData.id} onClick={this.reply_click}>{dynamicData.name}</a>
reply_click(event) {
console.log(event.target.getAttribute('id'))
}
this.reply_click(this.id)
this is your component scope, which means every attribute you defined in your component can be accessed by this. Probably you did not define id in this component.
You probably wanna do
this.reply_click(dynamicData.id)
instead.
The this inside the arrow function is the same as the this outside it. The onclick is already aware of the correct this, so use it like this:
onClick={this.reply_click(this.id)}
Try this code. The code you have provided doesn't work because this is bound to the current React component, instead you could access id of the clicked element using e.target.id:
this.state.data.map((dynamicData, key) => {
<a href="/#/template" id={dynamicData.id} onClick={(e) => this.reply_click(e.target.id)}>{dynamicData.name}</a>
<button type="button" class="btn-lisa">Edit</button>
})
Unrelated, but still I want to note that you don't have to use <a href={"blah"} instead you can use <a href="blah" because the last one uses a string contant.

Categories

Resources