How to delete data from firebase realtime database - reactjs

I create one table where data get from firebase realtime database. I am adding one delete button on each row in table. Onclick on delete button data should be delete on front end and backend also. But my issue is that when I am click on delete button data is deleted but after refreshing page data get back, data is not deleted from backend. I don't get where I do mistake in code please anyone can help me to solve this issue.
I share my code below.
TableData.js
import React, { Component } from 'react'
import StartFirebase from "../firebaseConfig/index";
import { ref, onValue} from 'firebase/database';
const db = StartFirebase();
export class TableData extends Component {
constructor(props) {
super(props);
this.state = {
tableData: []
}
}
componentDidMount(props) {
const dbRef = ref(db, 'userRecord')
onValue(dbRef, (snapshot) => {
let records = []
snapshot.forEach(childSnapshot => {
let keyName = childSnapshot.key;
let data = childSnapshot.val()
records.push({ "key": keyName, "data": data })
})
this.setState({ tableData: records })
})
}
DeleteData = ({ id, e,props }) => {
fetch(`https://clientsdata-dd45a-default-rtdb.firebaseio.com/userRecord/:${id}.json`,{
method: 'DELETE',
header:{
Accept:"application/json",
"Content-Type":"application/json"
}
}).then((res) => {
res.json().then((resp) => {
window.alert('Are you sure wanted to delete data?: ' + id)
console.log(id) //display id of particule click
const tableData = this.state.tableData.filter((i) => i.id !== id) //if i.id !==id then show
this.setState({ tableData: tableData })
tableData.splice(id, 1)
this.setState({ tableData: tableData })
window.alert("You delete the data successfully!")
console.log(tableData)
})
})
}
render() {
return (
<div>
<table className="table table-bordered table table-hover">
<thead>
<tr>
<th>#</th>
<th scope="col">ID</th>
<th scope="col">Roll</th>
<th scope="col">Name</th>
<th scope="col">Address</th>
<th scope="col">Mobile</th>
</tr>
</thead>
<tbody>
{
this.state.tableData.map((row, id) => {
return (
<tr key={id}>
<th key={id} >{row.key}</th>
<th scope="row">{id+1}</th>
<td>{row.data.userData.RollNum}</td>
<td>{row.data.userData.Name}</td>
<td>{row.data.userData.Address}</td>
<td>{row.data.userData.mobile}</td>
<td>{<button className='btn btn-danger' key={row.id} value={row.data.userData.value} id={row.data.userData.value} onClick={(e) => this.DeleteData({id,e})}>Delete</button>}</td>
</tr>
)
})
}
</tbody>
</table>
</div>
)
}
}
export default TableData

Related

When add new row in table, old data is beeing like new

I create a table, where we can add new row with inputs.
I have 2 components: AddNewRow, which have some inputs for write new data, and TableComponent, which keep data about all rows.
TableComponent:
addRow(rowData){
let newData = this.state.data
console.log(newData)
newData.push(rowData)
console.log(newData)
this.setState({data: newData})
}
render() {
return(
<Table>
<thead>
<tr>
<th>ID</th>
<th>Name</th>
</tr>
</thead>
<tbody>
{this.state.data.map(row =>{
if (row.changeMode){
return(<ChangeRow key={row.id} inputData={row} changeMode={this.changeMode} changeData={this.changeData}/>)
}
else{
return (<TableRow key={row.id} data={row} changeMode={this.changeMode} deleteRow={this.deleteRow}/>)
}
})}
<AddNewRow rowData={{changeMode: false, id: '', name: ''}} addRow={this.addRow}/>
</tbody>
</Table>
)
}
AddNewRow:
export default function AddNewRow({rowData, addRow}){
const [row, setRow] = useState(rowData)
const changeCell = (e, index) =>{
let newRow = row
let key = Object.keys(newRow)[index]
newRow[key] = e.target.value
setRow(newRow)
}
return(
<tr>
{Object.keys(row).map((key, index) => {
if(key != 'changeMode'){
return <td><Input onChange={e => changeCell(e, index)}/></td>
}}
)}
<td><Button color='primary' onClick={() => {
addRow(row)}
}>Add</Button></td>
</tr>
)
}
And when I add a new row, old data is beeing as new.
In the changeCell you're mutating state (changing the same object) something you should avoid when dealing with state. You should make a copy of it.
let newRow = { ...row };

TableData.js:57 DELETE https://clientdata-dd88a-default-rtdb.firebaseio.com/userData.json/:$%7Bid%7D

"TableData.js:57 DELETE https://clientdata-dd35a-default-rtdb.firebaseio.com/userDataRecord.json/:$%7Bid%7D net::ERR_FAILED
TableData.DeleteData # TableData.js:57
onClick # TableData.js:152
TableData.js:57 Uncaught (in promise) TypeError: Failed to fetch"
I get this error on my delete button code.Delete button code cant identify the id of tabledatas. I am trying it but didn't get output. Please help me to solve this issue. I share my code.
tabledata.js file
const db = StartFirebase();
export class TableData extends Component {
constructor() {
super();
this.state = {
tableDatas: []
}
}
componentDidMount() {
const dbRef = ref(db, 'userDatas')
onValue(dbRef, (snapshot) => {
let records = []
snapshot.forEach(childSnapshot => {
let keyName = childSnapshot.key;
let data = childSnapshot.val()
records.push({ "key": keyName, "data": data })
})
this.setState({ tableDatas: records })
})
}
DeleteData=async(id)=>{
await fetch('https://clientdata-dc88a-default-rtdb.firebaseio.com/userDatas.json/:${id}',{
method:'DELETE'
}).then((res)=>{
res.json().then((resp)=>{
alert('delete', id)
})
})
}
render() {
return (
<div>
<table className="table table-bordered table table-hover" id="table-to-xls">
<thead>
<tr>
<th scope="col">ID</th>
<th scope="col">Sr</th>
<th scope="col">House No</th>
<th scope="col">Name</th>
<th scope="col">Action</th>
</tr>
</thead>
<tbody>
{
this.state.tableData.map((row, id) => {
return (
<tr key={id}>
<th scope="row">{id}</th>
<td>{row.data.userDatas.srno}</td>
<td>{row.data.userDatas.house}</td>
<td>{row.data.userDatas.nameMarathi}</td>
<td>{row.data.userData.name}</td>
<td>{<button onClick={()=>this.DeleteData(id)}>Delete</button>}</td>
</tr>
)
})
}
</tbody>
</table>
</div>
)
}
}
This URL is wrong:
https://clientdata-dc88a-default-rtdb.firebaseio.com/userDatas.json/:${id}
When accessing the Firebase Realtime Database's REST API, the .json extension always needs to be at the end of the URL.
So:
https://clientdata-dc88a-default-rtdb.firebaseio.com/userDatas/:${id}.json

No access to "this"

I'm working on a web-application using the MERN stack that displays a table of clients with their name, email, and phone number. I haven't implemented Redux quite yet, but I'm using 'uuid' to supplement data in the table until I can get the redux store set up. So far I have displaying the the list and adding a client to the list working fine, but I am having trouble with the pesky delete button.
This is the current ClientTable component
import React, { Component } from "react";
import { Table, Container, Button } from "reactstrap";
import { connect } from "react-redux";
import {
getClients,
addClient,
editClient,
deleteClient,
} from "../actions/clientActions";
import PropTypes from "prop-types";
const renderClient = (clients, index, id) => {
return (
<tr key={index}>
<td>
<Button
className="remove-btn"
color="danger"
size="sm"
onClick={() => {
this.setState((state) => ({
clients: state.clients.filter((client) => client.id !== id),
}));
}}
>
×
</Button>
</td>
<td>{clients.name}</td>
<td>{clients.email}</td>
<td>{clients.number}</td>
</tr>
);
};
class ClientTable extends Component {
componentDidMount() {
this.props.getClients();
}
onDeleteClick = (id) => {
this.props.deleteClient(id);
};
render() {
const { clients } = this.props.client;
// const { clients } = this.state;
return (
<Container id="listContainer">
<Table
id="listTable"
className="table-striped table-bordered table-hover"
dark
>
<tr class="listRow">
<thead id="tableHeader">
<tr>
<th id="listActions">Actions</th>
<th id="listName">Name</th>
<th id="listEmail">Email</th>
<th id="listNumber">Number</th>
</tr>
</thead>
<tbody class="listRow">{clients.map(renderClient)}</tbody>
</tr>
</Table>
</Container>
);
}
}
ClientTable.propTypes = {
getClients: PropTypes.func.isRequired,
client: PropTypes.object.isRequired,
};
const mapStateToProps = (state) => ({
client: state.client,
});
export default connect(mapStateToProps, {
getClients,
deleteClient,
addClient,
})(ClientTable);
This is the bit of code that is causing me issues
<Button
className="remove-btn"
color="danger"
size="sm"
onClick={() => {
this.setState((state) => ({
clients: state.clients.filter((client) => client.id !== id),
}));
}}
>
×
</Button>
When I click the "delete" button I keep getting TypeError: Cannot read property 'setState' of unedefined
I know the error is because of 'this' isn't bound to anything, but I'm uncertain how to bind it within an onClick event if that is even possible or what even to bind it to. I am just lost as to how to approach this problem. (I'm still quite new to React).
If anyone has any ideas it would be greatly appreciated!
move renderClient function to ClientTable, and use it as a method of this class.
class ClientTable extends Component {
componentDidMount() {
this.props.getClients();
}
renderClient = (clients, index) => {
return (
<tr key={index}>
<td>
<Button
className="remove-btn"
color="danger"
size="sm"
onClick={() => this.onDeleteClient(clients.id)}
>
×
</Button>
</td>
<td>{clients.name}</td>
<td>{clients.email}</td>
<td>{clients.number}</td>
</tr>
);
};
onDeleteClick = (id) => {
this.props.deleteClient(id);
};
render() {
const { clients } = this.props.client;
// const { clients } = this.state;
return (
<Container id="listContainer">
<Table
id="listTable"
className="table-striped table-bordered table-hover"
dark
>
<tr class="listRow">
<thead id="tableHeader">
<tr>
<th id="listActions">Actions</th>
<th id="listName">Name</th>
<th id="listEmail">Email</th>
<th id="listNumber">Number</th>
</tr>
</thead>
<tbody class="listRow">{clients.map(this.renderClient)}</tbody>
</tr>
</Table>
</Container>
);
}
}

Keys should be unique so that components maintain their identity across updates

I have A react component which renders a list of items that have been called from an API and set to setOfAllBooks state. Any time I search for the item, setOfAllBooks state is filtered through by the search ternm and the results are held in searchedBooks state. The results of searchedBooks are then passed to Table component and rendered in a list. At this point it works correctly, but when I search for another item it gets clustered in the Table. What I want to do is anytime I search a new Item after I have searched for a previos term I want the list-items in the Table component to be cleared to make way for the new items that have been searched.
import React, { Component } from 'react';
import './Home.css'
import axios from 'axios';
import Autosuggest from 'react-autosuggest';
var books = []
const getSuggestions = value => {
const inputValue = value.trim().toLowerCase();
const inputLength = inputValue.length;
return inputLength === 0 ? [] : books.filter(book =>
book.title.toLowerCase().slice(0, inputLength) === inputValue);
};
const getSuggestionValue = suggestion => suggestion.title;
const renderSuggestion = suggestion => (
<div>
{suggestion.title}
</div>
);
const Table = ({ data }) => (
<table class="table table-hover">
<thead>
<tr class="table-primary">
<th scope="col">Title</th>
<th scope="col">Author</th>
<th scope="col">ISBN</th>
<th scope="col">No. Of Copies</th>
</tr>
</thead>
<tbody>
{data.map(row =>
<TableRow row={row} />
)}
</tbody>
</table>
)
const TableRow = ({ row }) => (
<tr class="table-light">
<th scope="row" key={row.title}>{row.title}</th>
<td key={row.author}>{row.author}</td>
<td key={row.isbn}>{row.isbn}</td>
<td key={row.isbn}>24</td>
</tr>
)
class Home extends Component {
constructor(props) {
super(props);
this.state = {
value: '',
suggestions: [],
setOfAllBooks: [],
searchedBooks: []
};
this.searchBook = this.searchBook.bind(this);
}
componentDidMount(){
axios.get('/api/book/viewAll')
.then(res => {
this.setState({ setOfAllBooks: res.data });
books = this.state.setOfAllBooks;
console.log(this.state.setOfAllBooks)
})
}
onChange = (event, { newValue }) => {
this.setState({
value: newValue
});
};
onSuggestionsFetchRequested = ({ value }) => {
this.setState({
suggestions: getSuggestions(value)
});
};
onSuggestionsClearRequested = () => {
this.setState({
suggestions: []
});
}
searchBook(event){
event.preventDefault();
this.setState({value: this.state.value});
this.state.searchedBooks = this.state.setOfAllBooks.filter(book => book.title == this.state.value);
this.setState({searchedBook: []})
console.log(this.state.searchedBook);
}
render() {
const { value, suggestions } = this.state;
const inputProps = {
placeholder: 'Enter the name of the book',
value,
onChange: this.onChange
}
return (
<div class="form-group col-lg-4">
<label for="exampleInputEmail1">Email address</label>
<Autosuggest
suggestions={suggestions}
onSuggestionsFetchRequested={this.onSuggestionsFetchRequested}
onSuggestionsClearRequested={this.onSuggestionsClearRequested}
getSuggestionValue={getSuggestionValue}
renderSuggestion={renderSuggestion}
inputProps={inputProps}
id="searchFor"
/>
<div className=" form-group">
<label htmlFor="searchFor"> </label>
<button class="form-control btn btn-success" type="submit" onClick={this.searchBook}>Search</button>
</div>
<Table data={this.state.searchedBooks} />
</div>
)
}
}
export default Home;
The results
The Error
You need to add the key prop to the TableRow component as <TableRow key={row.title} row={row} />. Remove the key where you have right now.
.... A good rule of thumb is that elements inside the map() call need keys.
... keys used within arrays should be unique among their siblings. . Doc.
So, it seems title what you used for key will still throw warnings, as they are not uniqe. If you have ID attribute in the row object use that. Adding key to TableRow will remove the first warning, but other warning still be there until title doesn't have the uniq values across all the data.

not getting any output while mapping an array of objects and displaying table rows in React JS

I have an array of objects and I want to display it's values in a Table
This is how my array looks like:
[{name: 'x', mobile: 'xxx'}, {name: 'y', mobile: 'yyy'}, ......]
I want to display it inside a table.
This is what I tried so far
import React, { Component } from 'react';
import {
Table,
ProgressBar
}
from 'react-bootstrap';
class Display extends Component {
render() {
var records = this.props.googleData;
const API = this.props.api;
const placeURI = this.props.placeURI;
var rows = [];
for(let p_id of records.results){
let dataURI = `${placeURI}${p_id.place_id}${API}`;
let proxyUrl = 'https://cors-anywhere.herokuapp.com/',
targetUrl = dataURI
fetch(proxyUrl + targetUrl)
.then((res) => res.json())
.then((data) => {
let jsonData = JSON.parse(JSON.stringify(data));
//console.log(jsonData);
rows.push(jsonData.result);
})
.catch((e)=> console.log(`Error! ${e.message}`));
}
console.log(rows);
return (
<div>
<ProgressBar now={45} />
<Table striped bordered condensed hover responsive>
<thead>
<tr>
<th>#</th>
<th>Name</th>
<th>Full Address</th>
<th>Phone Number</th>
<th>International P.no</th>
<th>Website</th>
<th>Rating</th>
</tr>
</thead>
<tbody>
{rows.map(( listValue, index ) => {
return (
<tr key={index}>
<td>{listValue.name}</td>
<td>{listValue.title}</td>
<td>{listValue.price}</td>
</tr>
);
})}
</tbody>
</Table>
</div>
);
}
}
export default Display;
This is how my array looks
But the map() is not returning any row. And if there is any suggestion by which I can improve my code is extremely appreciable. Please help
import React, { Component } from 'react';
import {
Table,
ProgressBar
}
from 'react-bootstrap';
class Display extends Component {
constructor(props) {
super(props);
this.state={
rows: []
}
}
componentDidMount = () => {
var records = this.props.googleData;
const API = this.props.api;
const placeURI = this.props.placeURI;
var rows = [];
for (let p_id of records.results) {
let dataURI = `${placeURI}${p_id.place_id}${API}`;
let proxyUrl = 'https://cors-anywhere.herokuapp.com/',
targetUrl = dataURI
fetch(proxyUrl + targetUrl)
.then((res) => res.json())
.then((data) => {
let jsonData = JSON.parse(JSON.stringify(data));
//console.log(jsonData);
rows.push(jsonData.result);
})
.catch((e) => console.log(`Error! ${e.message}`));
}
this.setState({
rows:rows
})
console.log(rows);
};
render() {
return (
<div>
<ProgressBar now={45} />
<Table striped bordered condensed hover responsive>
<thead>
<tr>
<th>#</th>
<th>Name</th>
<th>Full Address</th>
<th>Phone Number</th>
<th>International P.no</th>
<th>Website</th>
<th>Rating</th>
</tr>
</thead>
<tbody>
{this.state.rows.map(( listValue, index ) => {
return (
<tr key={index}>
<td>{listValue.name}</td>
<td>{listValue.title}</td>
<td>{listValue.price}</td>
</tr>
);
})}
</tbody>
</Table>
</div>
);
}
}
export default Display;

Resources