How to remove an element in reactjs by an attribute? - reactjs

I want to get unknown key attribute using known ID so that i may delete corresponding div.
I tried using document.getElementById("a").getAttribute('key'); , but it isn't working. May be my concept is wrong.
class PostAdded extends Component {
constructor(props) {
super();
this.deletepost = this.deletepost.bind(this);
}
deletepost() {
let ab =document.getElementById("a").getAttribute('key');
console.log(ab)
}
render() {
return (
<div>
{ this.props.posts.map((post, i) =>
<div id="a" key={`i-${post.title}`}>
<span> <h3>{post.title}</h3><p>{post.post}</p></span>
<input type="button" value="Delete" onClick={this.deletepost}/>
</div>
) }
</div>
)
}
}
export default PostAdded;

If you were able to delete the div, that probably wouldn't end up working for you anyway because any state change would cause a re-render and it would appear again. Instead, you could keep track of your posts in state and then remove one of the posts from state in your deletepost method.
class PostAdded extends Component {
constructor(props) {
super();
this.state = {
posts: props.posts
}
this.deletepost = this.deletepost.bind(this);
}
deletepost(index) {
const newPosts = this.state.posts.splice(index)
this.setState({posts: newPosts})
}
render() {
return (
<div>
{ this.state.posts.map((post, i) =>
<div id="a" key={`i-${post.title}`}>
<span> <h3>{post.title}</h3><p>{post.post}</p></span>
<input type="button" value="Delete" onClick={() => this.deletepost(i)}/>
</div>
) }
</div>
)
}
}
export default PostAdded;

Related

Handle multiple child component in React

I've tried to look everywhere and couldn't find anything related to my use case, probably I'm looking for the wrong terms.
I have a situation where I have a bar with 3 icons, I'm looking for set one icon "active" by changing the class of it.
The icon is a custom component which have the following code
export default class Icon extends Component {
state = {
selected : false,
}
setSelected = () => {
this.setState({
selected : true
})
}
setUnselected = () => {
this.setState({
selected : false
})
}
render() {
var classStatus = '';
if(this.state.selected)
classStatus = "selected-icon"
else
classStatus = "icon"
return <div className={classStatus} onClick={this.props.onClick}><FontAwesomeIcon icon={this.props.icon} /></div>
}
}
In my parent component I have the following code
export default class MainPage extends Component {
handleClick(element) {
console.log(element);
alert("Hello!");
}
render() {
return (
<div className="wrapper">
<div className="page-header">
<span className="menu-voice">File</span>
<span className="menu-voice">Modifica</span>
<span className="menu-voice">Selezione</span>
</div>
<div className="page-main">
<span className="icon-section">
<div className="top-icon">
<Icon icon={faFileCode} onClick={() => this.handleClick(this)} />
<Icon icon={faCodeBranch} onClick={() => this.handleClick(this)} />
<Icon icon={faMagnifyingGlass} onClick={() => this.handleClick(this)} />
</div>
</span>
<span className="files-section">Files</span>
<span className="editor-section"></span>
</div>
<div className="page-footer">
Footer
</div>
</div>
);
}
}
What I'm trying to achieve is that when one of the Icon child component get clicked it will set the selected state to true manage by the parent component, in the same time while one of them is true I would like that the parent would set to false the other twos.
I've tried to use the useRef function but it doesn't look as a best practise.
Which is the correct way to do it? Sending also this to the handleClick function it just return the MainPage class instead of the child. Any suggestion at least where I should watch?
Thanks in advance
I suggest not storing the state in the icon, since it doesn't know what else you're using it for. Simply have the icon component take it's 'selected' status from props. e.g.
export default class Icon extends Component {
render() {
var classStatus = '';
if(this.props.selected)
classStatus = "selected-icon"
else
classStatus = "icon"
return (
<div className={classStatus} onClick={this.props.onClick}>.
<FontAwesomeIcon icon={this.props.icon} />
</div>
);
}
};
Then you can just manage the state in the parent where it should be:
export default class MainPage extends Component {
constructor(props) {
super(props);
this.state = { selectedOption : '' };
}
handleSelectOption(newValue) {
this.setState({ selectedOption: newValue });
}
isSelected(value) {
return value === this.state.selectedOption;
}
render() {
return (
<div className="wrapper">
{ /* etc... */ }
<div className="page-main">
<span className="icon-section">
<div className="top-icon">
<Icon
icon={faFileCode}
onClick={() => this.handleSelectOption("File")}
selected={isSelected("File")}
/>
<Icon
icon={faCodeBranch}
onClick={() => this.handleSelectOption("Modifica")}
selected={isSelected("Modifica")}
/>
{ /* etc... */ }
</div>
</span>
</div>
{ /* etc... */ }
</div>
);
}
};
You should define a constructor in your class component:
constructor(props) {
super(props);
this.state = { selected : false };
}
You also have to call a function which modify the state when you click on the Icon. onClick={this.props.onClick} doesn't change the state

How to pass methods with parameters to children in React? (Cannot read property 'props' of undefined)

I'm currently making a to-do list, but unfortunately ran into some errors where I am unable to pass methods to a child component.
const React = require('react');
class App extends React.Component {
constructor(props){
super(props)
this.state = {
items: [],
input: ""
}
this.inputChange = this.inputChange.bind(this);
this.addItems = this.addItems.bind(this);
this.remItems = this.remItems.bind(this);
}
inputChange(event){
this.setState({
input: event.target.value
})
}
addItems(){
event.preventDefault()
const temp = this.state.input
this.setState({
input: "",
items: this.state.items.concat(temp)
})
}
remItems(id){
const temp = [...this.state.items]
const updatedItems = temp.filter(item => item.id!==id)
this.setState({
items: updatedItems
})
}
render(){
return (
<div class = "w-100 p-3">
<p>Enter your item here:</p>
<form onSubmit = {this.addItems} class="form.inline">
<input class = "form.control mb-2 mr-sm-2" value = {this.state.input} onChange = {this.inputChange}/>
<button type="submit" class="btn btn-primary mb-2">Add</button>
</form>
<UnorderedList items={this.state.items} remove = {this.remItems}/>
</div>
);
}
}
class UnorderedList extends React.Component {
constructor(props){
super(props)
}
render(){
return (
<ul>
{this.props.items.map(function(item, i) {
return (<div id = "entry" class = "d-flex">
<li key={i}>{item}</li>
{console.log(i)}
<button class = 'btn btn-sm btn-primary ml-auto' onClick = {() => this.remItems}> Done! </button>
</div>)
})}
</ul>
)
}
}
I expected to be able to remove the items by id key but it gives me "Cannot read property 'props' of undefined". Thanks for your help!

Reactjs - how to append a font-awesome icon to ref

I'm trying to use appendChild to add a fontawesome icon to a ref in react. I get the error:
Failed to execute 'appendChild' on 'Node': parameter 1 is not of type 'Node'.
Using append instead of appendChild can only add text.
class Example extends React.Component {
handle = (e) => {
e.target.appendChild('<i className="fas fa-minus-circle"/>')
}
render() {
return (
<div className="container">
<button onClick={this.handle}>CLICK HERE</button>
</div>
)
}
}
Consider changing your approach a little. You can achieve the same result you're expecting with the code below, and it's a little more common to use state and conditional JSX in React:
class Example extends React.Component {
state = { images: [] }
handle = () => {
this.setState({ images: [...images, 'fas fa-minus-circle'] });
}
render() {
return (
<div className="container">
<button onClick={this.handle}>CLICK HERE</button>
{this.state.images.map((image, index) => {
<i key={index} className={image} />
})}
</div>
);
}
}
You can create ref and attach it to the element you want to add the icon.
class Example extends React.Component{
constructor(props){
super(props);
this.iconRef= React.createRef();
}
handle = (e) => {
e.prenventDefault();
this.iconRef.current.appendChild('<i className="fas fa-minus-circle"/>')
}
render() {
return (
<div className="container">
<button ref={this.iconRef} onClick={this.handle}>CLICK HERE</button>
</div>
)
}
}

How to add conditional statement to React data.map function

I'm a React newbie and have a component which is outputting a checkbox list by mapping an array. This is the code that presently works.
export default class First extends React.Component {
constructor(props) {
super(props);
this.state = {
data: data,
};
}
render() {
return (
<div>
{this.state.data.map(d =>
<label key={ d.name } className="control control--checkbox">{d.name}
<input type="checkbox"/>
<div className="control__indicator"></div>
</label>)}
</div>
);
}
}
What I need to do is add an if/else telling the return map function only to render the checkbox list if another variable in the array (called domain) = "HMO". I'm really struggling with the syntax. I think it needs to be inserted below the {this.state.data.map(d => line but am really stuck. Any help would be greatly appreciated.
I believe you're looking for something like this.
export default class First extends React.Component {
constructor(props) {
super(props);
this.state = {
data: data,
};
}
render() {
return (
<div>
{this.state.data.map(d => {
if(d.domain === "HMO"){
return (
<label key={ d.name } className="control control--checkbox">{d.name}
<input type="checkbox"/>
<div className="control__indicator" />
</label>
)}
return null
})}
</div>
)
}
}
The .map function will iterate through each element in your data array, it will then check if that element's domain variable is equal to the string "HMO". If it is, it will return the html that displays the checkbox, otherwise it will return null.
Use Array.filter:
export default class First extends React.Component {
constructor(...args) {
super(...args);
this.state = {
data: data
};
}
getItems() {
return this.state.data
.filter(d.domain === "HMO")
.map(d => (
<label key={ d.name } className="control control--checkbox">{d.name}
<input type="checkbox"/>
<div className="control__indicator"></div>
</label>
));
}
render() {
return (
<div>
{this.getItems()}
</div>
);
}
}
The downside is that you loop twice compared to #MEnf's solution so it can be slower if you have a really long array. The upside is that it looks neater (I know that is quite subjective).

Reactjs multiple form submit

In my case, i would like to submit multiple forms in reactjs. But i have no idea on how to get the multiple form at Parent Component and submit.
here is my code:
class BulkEditor extends React.Component {
constructor(props) {
super(props);
this.state = {
items: [],
customCompanies: []
};
this.forms = [];
this.onAddChild = this.onAddChild.bind(this);
this.handleBulkSaveClick = this.handleBulkSaveClick.bind(this);
}
handleBulkSaveClick(event) {
event.preventDefault();
}
/*
* -- Add Children
*/
onAddChild() {
this.state.items.push(BulkEditorForm.defaultProps);
this.setState({
items: this.state.items
});
}
render() {
var forms = this.state.items.map(function(item, index) {
return (
<li className="list-group-item" key={index}>
<BulkEditorForm companies={this.state.customCompanies} item={item}
ref="editorform"></BulkEditorForm>
</li>
);
}.bind(this));
return (
<ul className="list-group">
{forms}
<li className="list-group-item">
<div className="btn-group btn-group-sm pull-right" role="group" aria-label="bulk-buttons">
<a href="javascript:;" className="btn btn-primary" onClick={this.onAddChild.bind(this)}>
<span className="glyphicon glyphicon-plus"></span>
</a>
<a href="javascript:;" className="btn btn-default" onClick={this.handleBulkSaveClick}>Bulk Save</a>
</div>
<div className="clearfix"></div>
</li>
</ul>
);
}
}
Here is next class
export default class BulkEditorForm extends React.Component {
constructor(props) {
super(props);
this.handleFormSubmit = this.handleFormSubmit.bind(this);
}
handleFormSubmit(event) {
event.preventDefault();
alert("Submit");
}
render() {
return (
<form action='#' method="post" onSubmit={this.handleFormSubmit}>
<button type="submit" className="btn btn-link">Save</button>
</form>
);
}
}
In your loop of rendering form list, use different ref value for each form:
<BulkEditorForm companies={this.state.customCompanies} item={item}
ref={"editorform"+index}></BulkEditorForm>
Then after all forms are rendered, access the form list by refs in your Parent Component, which means adding componentDidMount() function as follows:
class BulkEditor extends React.Component {
constructor(props) {
}
componentDidMount() {
//using basic javascript "FOR" loop ^^
for (i = 0; i < this.state.items.length; i++) {
this.forms.push(this.refs["editorform"+index]);
}
}
}
I didn't have time for testing all the code, but that's the idea! If it doesn't work yet, feel free to post here some error logs, then we may solve it together, thanks ^^

Resources