ReactJS remove dynamic element - javascript

i want to remove dynamic element in my program, but i think, i have problem with 'this'.When i click in 'X', nothing happens, console doesn't show any error. Maybe someone more experienced will help me.
('items' is array in state)
Main file:
removeItemCity(i){
let arr = this.state.items;
arr.splice(i, 1);
this.setState({items:arr})
}
renderItems(item,i){
return(<Tiles key = {'key_' + i} index = {i} delete = {() =>
{this.removeItemCity}}/>);
}
render() {
return(
<div className = "BodyAppContainer">
<div className = "grid" id="items">
{this.state.items.map(this.renderItems) }
</div>
</div>
);
}
And my component "Tiles"
import React from 'react';
class Tiles extends React.Component {
constructor(props) {
super(props);
}
remove(){
this.props.delete(this.props.index);
}
render() {
return (
<div className = "col-4_sm-6_xs-12 item">
<h2>City : {this.props.index}</h2>
<button className="removeButton" onClick={() => this.remove} >X</button>
</div>
);
}
}
export default Tiles;

Your onClick prop for the X button is not doing anything:
onClick={() => this.remove}
When you click, it calls that arrow function. But that arrow function only has this.remove, which is the definition to a method. The first step in helping you out is you should call that method using parentheses:
onClick={() => this.remove()}
The same thing applies to your renderItems(), where you are also missing parentheses to enact a function call in the delete prop passed to Tiles:
delete={() => {this.removeItemCity}}

Try this:
<button className="removeButton" onClick={this.remove} >X</button>

Related

Value not getting passed from child to parent component in React

As you can see in the two components below, i want to delete the recipes(in app component) from a button click in the panelcomponent,
i have a method in app to delete the recipe, and a prop(onclick) send to child panelcomponent. Panel then gets the index from the map of recipes, and after the button click it executes the handleDelet method to send the index back to parent. but No this is not working !
class App extends React.Component {
state={
addRecipe:{recipeName:"",ingredients:[]},
recipes:[{recipeName:"Apple",ingredients:["apple","onion","spice"]},
{recipeName:"Apple",ingredients:["apple","onion","spice"]},
{recipeName:"Apple",ingredients:["apple","onion","spice"]}]
}
handleDelete = (index) => {
let recipes = this.state.recipes.slice();
recipes.splice(index,1); //deleting the index value from recipe
this.setState({recipes}) //setting the state to new value
console.log(index,recipes)
}
render() {
return (
<div className="container">
<PanelComponent recipes={this.state.recipes} onClick={()=>this.handleDelete(index)}/>
<ModalComponent />
</div>
);
}
}
class PanelComponent extends React.Component {
handleDelete = (index) => {
this.props.onClick(index); //sending index to parent after click
console.log(index)
}
render() {
return (
<PanelGroup accordion>
{this.props.recipes.map( (recipe,index) => {
return(
<Panel eventKey={index} key={index}>
<Panel.Heading>
<Panel.Title toggle>{recipe.recipeName}</Panel.Title>
</Panel.Heading>
<Panel.Body collapsible>
<ListGroup>
{recipe.ingredients.map((ingredient)=>{
return(<ListGroupItem>{ingredient}</ListGroupItem>);
})}
</ListGroup>
<Button bsStyle="danger" onClick={()=>this.handleDelete(index)}>Delete</Button>
<EditModalComponent />
</Panel.Body>
</Panel>
);
})}
</PanelGroup>
);
}
}
Thea actual error in your code is that while using arrow function in the onClick in parent, you are passing the wrong parameter, instead of {()=>this.handleDelete(index)} what you should write is
{(value)=>this.handleDelete(value)}, However, that also not necessary and you could simple write {this.handleDelete} in App since your handleDelete function is already binded and it received the values from the Child component.
render() {
return (
<div className="container">
<PanelComponent recipes={this.state.recipes} onClick={(value)=>this.handleDelete(value)}/>
<ModalComponent />
</div>
);
}
The difference in writing {()=>this.handleDelete(index)} vs {(value)=>this.handleDelete(value)} is that in the first case, you are explicitly passing the index that you get from the map function in your App component while in the second case, the value passed from the child component when you execute this.props.onClick(value) is being provided to the handleDelete function.
you are sending the function wrongly as props. you are sending the result of the function as props rather than the function itself
class App extends React.Component {
state={
addRecipe:{recipeName:"",ingredients:[]},
recipes:[{recipeName:"Apple",ingredients:["apple","onion","spice"]},
{recipeName:"Apple",ingredients:["apple","onion","spice"]},
{recipeName:"Apple",ingredients:["apple","onion","spice"]}]
}
handleDelete = (index) => {
let recipes = this.state.recipes.slice();
recipes.splice(index,1); //deleting the index value from recipe
this.setState({recipes}) //setting the state to new value
console.log(index,recipes)
}
render() {
return (
<div className="container">
//change here
<PanelComponent recipes={this.state.recipes} onClick={this.handleDelete}/>
<ModalComponent />
</div>
);
}
}

React. Managing state with onClick function using index

Okay, So I am still fairly new to coding. I am trying to manage the state of my calculator using an onClick function. I have a list of ingredients in my database. I have it set up so I can pull all of them from the db and its listed on my component. I am trying to set it so when i click on the individual name it will change the properties listed below. I feel like im on the right track but cant seem to figure it out.
import React, { Component } from 'react';
import $ from 'jquery';
import '../index.css';
class StepFive extends Component{
constructor(props) {
super(props)
this.state = {
ingredients: false,
counter: 0
}
}
componentDidMount() {
var self = this;
$.ajax({
method: 'GET',
url: 'http://localhost:3002/api/ingredients',
})
.done(function(ingredients){
self.setState({ingredients: ingredients})
})
}
handleChange(e){
this.setState({counter: e.target.value})
}
listAll(){
return (
<div>
<div className="vertical-menu">
{this.state.ingredients.map(function(ingredients, i){
console.log(i)
return <div>
<span><a key={i} href="#" onClick={this.handleChange(i)}>{ingredients.name}</a> <a href='#'>+</a></span>
</div>
})}
</div>
</div>)
}
render() {
console.log(this.state, 'in render')
if(this.state.ingredients === false){
return(<div><span>loading</span></div>)
} else {
return(
<div className='stepFiveBox'>
{this.listAll()}
<ul>
<li>Hardness=
{this.state.ingredients[this.state.counter].hardness}</li>
<li>Cleansing={this.state.ingredients[this.state.counter].cleansing}</li>
<li>Condidtion={this.state.ingredients[this.state.counter].condition1}</li>
<li>Bubbly={this.state.ingredients[this.state.counter].bubbly}</li>
<li>Creamy={this.state.ingredients[this.state.counter].creamy}</li>
<li>Iodine={this.state.ingredients[this.state.counter].iodine}</li>
<li>INS={this.state.ingredients[this.state.counter].ins}</li>
<li>Lauric={this.state.ingredients[this.state.counter].lauric}</li>
<li>Myristic={this.state.ingredients[this.state.counter].myristic}</li>
<li>Palmitic={this.state.ingredients[this.state.counter].palmitic}</li>
<li>Stearic={this.state.ingredients[this.state.counter].stearic}</li>
<li>Ricinoleic={this.state.ingredients[this.state.counter].rincinoleic}</li>
<li>Oleic={this.state.ingredients[this.state.counter].oleic}</li>
<li>Linoleic={this.state.ingredients[this.state.counter].linoleic}</li>
<li>Linolenic={this.state.ingredients[this.state.counter].linolenic}</li>
<li>NaOH SAP={this.state.ingredients[this.state.counter].sap}</li>
</ul>
</div>
)
}
console.log(this.listAll(),)}
}
export default StepFive
A problem is in your onClick handler. You're doing
<span onClick={this.handleChange(i)}></span>
Which is invoking handleChange at render time.
In order to invoke the function on click, you just pass the function without calling it.
<span onClick={this.handleChange(i)}></span>
In order to pass specific arguments to the function, you have two options:
<span onClick={() => this.handleChange(i)}></span>
or:
<span onClick={this.handleChange.bind(this, i)}></span>
Here's an example using the .bind syntax:
https://codesandbox.io/s/Z461QVox8
can you try to replace this one :
handleChange(e){
this.setState({counter: e.target.value})
}
to this one :
handleChange = (e) => {
this.setState({counter: e.target.value})
}
and replace this one too :
<a key={i} href="#" onClick={this.handleChange(i)}>
to this one :
<a key={i} href="#" onClick={() => this.handleChange(i)}>
Hope can help you :)
it was this issues.
in the listAll function i added a
var self = this;
then switched all this to self. was getting error value undefined... so i realized i didnt need e.target.value i jsut needed e.
changed handelChange function to
handleChange = (e) => {
this.setState({counter: e});
}
badabingbadaboom

Issue Utilizing Dynamic Attributes in React

My goal is to have the function handleClick() alert the squareNum for any Square Object clicked, as can be seen in the code below. Though implementation of such isn't working. At first, I tried implementing in accordance to this link , through binding - but no success.
After further research, I suspect the binding issue exists since upon click the square object created isn't identified, but rather the html rendered (the actual button).
As such I created the data-id attribute within the rendered button html that retrieves data from the square object. I proceeded to implement in accordance to this link.
Unfortunately, I get the error that getAttributes isn't defined, and not too sure what's wrong.
Along with the solution for the getAttributes issue, is there a better way to implement this, so the respective squareNum is identified upon click?
Thanks in advance
CODEPEN
CODE
class Square extends React.Component {
//constructor
constructor() {
super();
this.state = {
value: null,
squareNum: null,
};
}
render() {
return (
//<button className="square" onClick = {() => this.setState({value: 'X'})}>
// <button className = "square" data-id = {this.props.squareNum} onClick = {() => this.props.onClick()}>
<button className="square" data-id = {this.props.squareNum} onClick = {this.onClickSquare()}>
{this.props.value}
</button>
);
}
onClickSquare() {
this.props.onClick(this.props.squareNum);
}
}
class Board extends React.Component {
constructor() {
super();
this.state = {
squares: Array(9).fill(null),
};
}
renderRow(i) {
var rowSquare = [];
var square;
//{objects.map((o, i) => <ObjectRow obj={o} key={i}/>}
// create row of 3, creating square elements in array then return array
for(var iterator = i; iterator < i+3; iterator++) {
square = <Square key = {iterator} squareNum = {iterator} value = {this.state.squares[iterator]} onClick = {() => this.handleClick} />;
rowSquare.push(square);
}
return <div className ="board-row">
{rowSquare}
</div>
} // end of renderRow()
render() {
const status = 'Next player: X';
return (
<div>
<div className="status">{status}</div>
{this.renderRow(0)}
{this.renderRow(3)}
{this.renderRow(6)}
</div>
);
}
handleClick(squareId) {
// utilize slice to copy not change state
// want to keep mutating changes to setState only
const squares = this.state.squares.slice();
alert(squareId);
//squares[i] = 'X';
this.setState({squares: squares});
} // end of handleClick
}
class Game extends React.Component {
render() {
return (
<div className="game">
<div className="game-board">
<Board />
</div>
<div className="game-info">
<div>{/* status */}</div>
<ol>{/* TODO */}</ol>
</div>
</div>
);
}
}
There are a few issues with your example, primarily that you're not passing props to the parent class. Furthermore, your onClick handlers require functions. ES6 arrow functions will implicitly bind the context, so you can wrap your handlers in an anonymous callback. As for the getAttributes error, my guess is that you were trying to query the DOM for that attribute, but you weren't selecting the element properly or keeping a reference to it. Regardless, the rest should be fairly straight forward and you wouldn't need to use the data-id attribute at all. See https://codepen.io/anon/pen/Kavmyz?editors=0010
class Square extends React.Component {
//constructor
constructor(props) {
super(props);
this.state = {
value: null,
squareNum: null,
};
}
render() {
return (
<button className="square" onClick = {() => this.onClickSquare()}>
{this.props.value}
</button>
);
}
onClickSquare() {
this.props.onClick(this.props.squareNum);
}
}
class Board extends React.Component {
constructor() {
super();
this.state = {
squares: Array(9).fill(null),
};
}
renderRow(i) {
var rowSquare = [];
var square;
// create row of 3, creating square elements in array then return array
for(var iterator = i; iterator < i+3; iterator++) {
square = ( <Square
key={iterator}
squareNum={iterator}
value={this.state.squares[iterator]}
onClick={(squareNum) => this.handleClick(squareNum)} />);
rowSquare.push(square);
}
return <div className ="board-row">
{rowSquare}
</div>
} // end of renderRow()
render() {
const status = 'Next player: X';
return (
<div>
<div className="status">{status}</div>
{this.renderRow(0)}
{this.renderRow(3)}
{this.renderRow(6)}
</div>
);
}
handleClick(squareId) {
// utilize slice to copy not change state
// want to keep mutating changes to setState only
const squares = this.state.squares.slice();
squares[squareId] = squareId;
this.setState({squares: squares});
} // end of handleClick
}
Hope this helps!

React.js and ES2015 - Pass a method from parent to child

I'm trying to remove the child element(Note) when a user click the remove button. The remove method is on parent(Board) and I try to pass it to child thru props, but it is not working.
I try to use simple remove, this.remove - not defined remove, or this, this.remove.bind(this) nothing seems to work;location: eachNote(text,i) method
import React from 'react';
import ReactDOM from 'react-dom';
class Note extends React.Component{
constructor(props){
super(props);
this.state = {editing: false};
}
edit() {
this.setState({editing: true});
}
save() {
let val = this.refs.newText.value;
this.setState({editing: false});
}
renderNormal(){
return (
<div>
<p>{this.props.children} </p>
<button type="button" onClick={this.edit.bind(this)}>Edit</button>
<button type="button" onClick={this.hRemove.bind(this)}>Remove</button>
</div>
);
}
renderForm(){
return (
<div>
<textarea ref="newText" defaultValue={this.props.children}></textarea>
<button type="button" onClick={this.save.bind(this)}>Saved</button>
</div>
);
}
render() {
if(this.state.editing ==true ) {return this.renderForm();}
else {return this.renderNormal();}
}
}
class Board extends React.Component{
constructor(props) {
super(props);
this.state = {comments: ['icecream','antimoniu','bentrans'] };
}
remove(i){
let arr = this.state.comments;
arr.splice(i,1);
this.setState({comments: arr});
}
eachNote(text,i) {
return (<Note key={i} index={i} hRemove={this.remove}>{text}</Note>);
}
render(){
return (
<div>
{this.state.comments.map(this.eachNote)}
</div>
);
}
}
ReactDOM.render(<Board />, document.getElementById('container'));
I tried Rafi Ud Daula Refat and Sven (thanks for answers) codes and the below one, but I still received the error: this is undefined;
in the Parent, I have:
eachNote(text,i) {
return (<Note key={i} index={i} hRemove={this.remove.bind(i)}>{text} </Note>);
}
in the Child, I have:
removed(i) {
this.props.hRemove(i);
}
renderNormal(){
return (
<div>
<p>{this.props.children} </p>
<button type="button" onClick= {this.edit.bind(this)}>Edit</button>
<button type="button" onClick= {this.removed.bind(this,i)}>Remove</button>
</div>
);
}
I tried also this.removed.bind(this) and this.removed.bind(i), hRemove={this.remove.bind(i)}, and their combinations not working
If you want to use one method of parent you should pass the function as a props to the child. and from child you can access it as
this.props.functionName
Here in your note Component
<button type="button" onClick={this.hRemove.bind(this)}>Remove</button>
But note component does not have any method named hRemove. It can be assed through
this.props.hRemove()
<button type="button" onClick={this.props.hRemove(idorsomething)}>Remove</button>
And as the function 'remove' in the parent component has one parameter. So from the Child component note you have pass variable a. then it will work. like
this.props.hRemove(id)
When you pass the function remove as a hRemoveprop to your Note, you can find it in this.props.hRemove.
You can also bind the Note directly to the passed remove function:
eachNote(text,i) {
return (<Note key={i} index={i} hRemove={this.remove.bind(i)}>{text}</Note>);
}
Then you simply use
<button type="button" onClick={this.props.hRemove}>Remove</button>
Keep in mind, with ES6 you don't have this in your custom render methods, this can be done in several ways: http://egorsmirnov.me/2015/08/16/react-and-es6-part3.html

React.js: How to append a component on click?

I'm new to React and I'm puzzled on something kind of basic.
I need to append a component to the DOM after the DOM is rendered, on a click event.
My initial attempt is as follows, and it doesn't work. But it's the best thing I've thought to try. (Apologies in advance for mixing jQuery with React.)
ParentComponent = class ParentComponent extends React.Component {
constructor () {
this.addChild = this.addChild.bind(this);
}
addChild (event) {
event.preventDefault();
$("#children-pane").append(<ChildComponent/>);
}
render () {
return (
<div className="card calculator">
<p><a href="#" onClick={this.addChild}>Add Another Child Component</a></p>
<div id="children-pane">
<ChildComponent/>
</div>
</div>
);
}
};
Hopefully it's clear what I need to do, and I hope you can help me attain an appropriate solution.
Don't use jQuery to manipulate the DOM when you're using React. React components should render a representation of what they should look like given a certain state; what DOM that translates to is taken care of by React itself.
What you want to do is store the "state which determines what gets rendered" higher up the chain, and pass it down. If you are rendering n children, that state should be "owned" by whatever contains your component. eg:
class AppComponent extends React.Component {
state = {
numChildren: 0
}
render () {
const children = [];
for (var i = 0; i < this.state.numChildren; i += 1) {
children.push(<ChildComponent key={i} number={i} />);
};
return (
<ParentComponent addChild={this.onAddChild}>
{children}
</ParentComponent>
);
}
onAddChild = () => {
this.setState({
numChildren: this.state.numChildren + 1
});
}
}
const ParentComponent = props => (
<div className="card calculator">
<p><a href="#" onClick={props.addChild}>Add Another Child Component</a></p>
<div id="children-pane">
{props.children}
</div>
</div>
);
const ChildComponent = props => <div>{"I am child " + props.number}</div>;
As #Alex McMillan mentioned, use state to dictate what should be rendered in the dom.
In the example below I have an input field and I want to add a second one when the user clicks the button, the onClick event handler calls handleAddSecondInput( ) which changes inputLinkClicked to true. I am using a ternary operator to check for the truthy state, which renders the second input field
class HealthConditions extends React.Component {
constructor(props) {
super(props);
this.state = {
inputLinkClicked: false
}
}
handleAddSecondInput() {
this.setState({
inputLinkClicked: true
})
}
render() {
return(
<main id="wrapper" className="" data-reset-cookie-tab>
<div id="content" role="main">
<div className="inner-block">
<H1Heading title="Tell us about any disabilities, illnesses or ongoing conditions"/>
<InputField label="Name of condition"
InputType="text"
InputId="id-condition"
InputName="condition"
/>
{
this.state.inputLinkClicked?
<InputField label=""
InputType="text"
InputId="id-condition2"
InputName="condition2"
/>
:
<div></div>
}
<button
type="button"
className="make-button-link"
data-add-button=""
href="#"
onClick={this.handleAddSecondInput}
>
Add a condition
</button>
<FormButton buttonLabel="Next"
handleSubmit={this.handleSubmit}
linkto={
this.state.illnessOrDisability === 'true' ?
"/404"
:
"/add-your-details"
}
/>
<BackLink backLink="/add-your-details" />
</div>
</div>
</main>
);
}
}

Categories