I try to update data in react firebase application. Everything work fine, i can recover the right data in a modal, and modify them.
But, when I set my data to firebase (with a function "updateContent), my entire collection of item is delete because I did not specify the exact path of the selected item. So, to do that, I need to recover the ID of the selected Item in my function. My problem: I manage to retrieve all the information of my element, but not its ID. I try many thing, console.log every function with ID item, every thing it's okay except for my modal and my function "updateContent" (while the other information of my element is displayed without any problem)
Can you give me a little help ? Thank you in advance.
This is my code for each item, when function to pass the data from my Hit Component to my modal Component (modal is for modify item data):
function handleClick (hit, onEdit) {
onEdit({id: hit.objectID, marque: hit.marque, numero: hit.numero, reference: hit.reference, marquesuite: hit.marquesuite, cote: hit.cote})
}
const Hit = ({hit, onEdit}) =>
<div className="item" id={hit.objectID}>
<img src={hit.avatarURL} width={150} height={150}></img>
<h1 className="marque">{hit.marque}</h1>
<h3 className="numero">{hit.numero}</h3>
<h4 className="reference">{hit.reference}</h4>
<h4 className="marquesuite">{hit.marquesuite}</h4>
<p className="cote">{hit.cote}</p>
<button className="btn btn-warning" onClick={() => handleClick(hit, onEdit) }>Modifier</button>
<button className="btn btn-danger" onClick={() => removeToCatalogue(hit)}>Supprimer</button>
</div>
const Content = ({ onEdit, }) => {
const EnhancedHit = props =>
<Hit onEdit={ onEdit } { ...props } />
return (
<div className="text-center">
<Hits hitComponent={ EnhancedHit } />
</div>
)
}
And now, this is my modal component:
updateContent = (e) => {
e.preventDefault();
const catalogue = {
marque: this.state.marque,
marquesuite: this.state.marquesuite,
numero: this.state.numero,
reference: this.state.reference,
cote: this.state.cote,
id: this.state.key,
}
console.log(catalogue)
//firebase.database().ref(`catalogue`/).set(catalogue);
};
onOpenModal = (hit) => {
this.setState({ open: true, id: hit.objectID, marque: hit.marque, numero: hit.numero, reference: hit.reference, marquesuite: hit.marquesuite, cote: hit.cote });
console.log(hit.marque, hit.id)
};
onCloseModal = () => {
this.setState({ open: false });
};
onInputChange(e) {
this.setState({
[e.target.name]: e.target.value
});
}
render (){
const { open } = this.state;
<h1 className="text-center">Catalogue de capsule</h1>
<InstantSearch
apiKey="xxx"
appId="xxx"
indexName="xxx>
<SearchBox translations={{placeholder:'Rechercher une capsule'}} width="500 px"/>
<Content onEdit={this.onOpenModal}/>
<Modal open={open} onClose={this.onCloseModal} center>
<form onSubmit={this.updateContent} key={this.state.objectID}>
<h2>Modification de la capsule :</h2>
<p>Marque de la capsule:<input type="text" class="form-control" name="marque" value={this.state.marque} onChange={this.handleChange}></input></p>
<p>Numéro de la capsule:<input type="text" class="form-control" name="numero" value={this.state.numero} onChange={this.handleChange}></input></p>
<p>Référence de la capsule:<input type="text" class="form-control" name="marquesuite" value={this.state.marquesuite} onChange={this.handleChange}></input></p>
<p>Référence de la capsule (suite):<input type="text" class="form-control" name="reference" value={this.state.reference}onChange={this.handleChange}></input></p>
<p>Cote de la capsule:<input type="text" class="form-control" name="cote" value={this.state.cote}onChange={this.handleChange}></input></p>
<button className="btn btn-success">Mettre à jour</button>
</form>
</Modal>
</InstantSearch>
I find the solution. It was just given the same name in id props like this:
onEdit({objectID: hit.objectID ...})
onOpenModal = (hit) => {
this.setState({ open: true, objectID: hit.objectID, ... });
};
Related
I'm having some issues with the useState hook and i can't understand why this doesn't work.
I'm building a simple ticket system, and whenever a user clicks on a button it opens a modal and the user can write things about their issue.
I'm having problems getting this modal data to display on another page, where the user can see all the tickets, like a list.
If i do a console.log i can see the user input, but if a try to print this into the page itself it doesn't work.
Throws an error saying TypeError: addTicket is not a function
And lastly i'd like to show the modal info in a format(ID - Title - Status), how can i proceed about the id part, for it to iterate itself every submit event?
Many thanks!
Code on the list page
const Home = () => {
const [showModal, setShowModal] = useState(false);
const openModal = () => {
setShowModal(prev => !prev)
}
const[tickets, setTickets] = useState([]);
const addTicket = ( title ) =>{
setTickets([...tickets, { title }])
}
return(
<>
<PageContainer>
<HeaderContainer>
<img src={ gugale } alt="logo-left"/>
<img src={ logo } alt="logo-right"/>
</HeaderContainer>
<TicketsContainer>
<CreateTicketModal showModal={ showModal } setShowModal= { setShowModal }/>
<TicketsTop>
<p>Seus tickets</p>
<button onClick={openModal}>Novo ticket</button>
</TicketsTop>
<TicketTitles>
<p>ID</p>
<p>Título</p>
<p>Status</p>
</TicketTitles>
<TicketsInfo>
{ tickets.map(ticket => {
<p> {ticket.name} </p>
})}
</TicketsInfo>
</TicketsContainer>
</PageContainer>
<GlobalStyle/>
</>
)
}
Code on the modal page
const CreateTicketModal = ({showModal, setShowModal, addTicket}) => {
const [ title, setTitle] = useState("");
const handleName = (e) => {
setTitle(e.target.value);
}
const handleSubmit = (e) => {
e.preventDefault();
addTicket(title);
}
return (
<>
{showModal ? (
<Background showModal={showModal}>
<ModalWrapper>
<ModalHeader>
<p className="createNew" >Criar Novo Ticket</p>
<button className="closebtn" onClick={() => setShowModal(prev => !prev)}><FiX className="icon"></FiX></button>
</ModalHeader>
<form onSubmit={ handleSubmit } >
<p className="ticketTitle">Título</p>
<input type="text" name="ticketInput" placeholder="Escreva uma breve descrição sobre o problema" required onChange={ handleName } className="titleInput"/>
<p className="dscptTitle">Descrição</p>
<textarea type="text" name="dscpInput" placeholder="Escreva detalhadamente a sua solicitação..." className="dscpInput"/>
<p className="anex">Anexos</p>
<p className="anexDscp">Envie-nos arquivos, imagens ou textos que possam contribuir para a verificação da solicitação</p>
<Anex>
<FiUploadCloud className="anexCloud"></FiUploadCloud>
<p>Arraste e solte arquivos aqui ou</p>
<button>Selecione aqui</button>
</Anex>
<button addTicket={ addTicket }className="addTkt">Adicionar ticket</button>
</form>
</ModalWrapper>
<GlobalStyle/>
</Background>
): null}
</>
)
}
I believe that you are missing to pass addTicket function as prop to the CreateTicketModal
component
<CreateTicketModal showModal={showModal} setShowModal= {setShowModal} addTicket={addTicket} />
You need to pass addTicket to the Modal component as props as <CreateTicketModal addTicket={addTicket} ... /> to access it in the child component.
I have developed a component which receive data from another component (father). The component who receives the data, the first time, show the data correctly, but the second time, don't do it.
The second time the metho componentWillReceiveProps is called and I have implemented this. But, despite that, the data is not refreshed.
To see the data of this second call, I need to send data to component child a third time and in this moment I will see the data of the second call.
The code of the component child is:
import React, {Component} from "react";
import { Button, Spinner } from "react-bootstrap";
import BootstrapTable from 'react-bootstrap-table-next';
import { columnsTTShootingFEB, sortedTTShootingFEB } from "../../FEBCOM/column.tables";
import ToolkitProvider from 'react-bootstrap-table2-toolkit';
import "../../../css/content.css";
/**
* This constat let me have a row with buttons who show or hide columns
*
* #param {*} param0
*/
const CustomToggleList = ({
columns,
onColumnToggle,
toggles
}) => (
<div className="btn-group btn-group-toggle" data-toggle="buttons" style = {{width: 100 + "%"}}>
{
columns
.map(column => ({
...column,
toggle: toggles[column.dataField]
}))
.map((column, index) => {
if (index > 1){
return (<button
type="button"
key={ column.dataField }
className={ `btn btn-success btn-sm ${column.toggle ? 'active' : ''}` }
data-toggle="button"
aria-pressed={ column.toggle ? 'true' : 'false' }
onClick={ () => onColumnToggle(column.dataField) }
>
{ column.text }
</button>)
}
})
}
</div>
);
class TTShooting extends Component{
constructor(props){
super(props);
this.props = props;
this.state = {
loaded: false
};
}
componentDidMount(){
console.log("Componente cargado");
console.log("id_team_club 1: " + this.props.teams_std_stats[0].id_team_club);
this.setState({
loaded: true,
teams_std_stats: this.props.teams_std_stats
});
}
componentWillReceiveProps(nextProps){
this.props = nextProps;
console.log("id_team_club 2: " + this.props.teams_std_stats[0].id_team_club);
this.setState({
teams_std_stats: this.props.teams_std_stats
});
console.log("Componente recibe nuevos datos");
}
render(){
return(
<div>
{
(this.state.loaded) ?
<div>
{
(this.props.language === "es") ?
<div>
<ToolkitProvider
keyField="id_team_club"
data={ this.state.teams_std_stats }
columns={ columnsTTShootingFEB }
columnToggle
>
{
props => (
<div>
<p className = "text-justify" style = {{fontSize: 12 + "pt"}}><b>Nota: </b>Para añadir o eliminar columnas en la tabla basta hacer clic sobre uno de estos botones</p>
<CustomToggleList { ...props.columnToggleProps } />
<hr />
<BootstrapTable
{ ...props.baseProps }
footerClasses = "footer-class"
defaultSorted = { sortedTTShootingFEB }
/>
</div>
)
}
</ToolkitProvider>
</div>
:
<h2>Pendiente de desarrollo</h2>
}
</div>
:
<div style = {{marginTop: 10 + "px"}}>
<Button variant="dark" disabled>
<Spinner
as="span"
animation="border"
size="sm"
role="status"
aria-hidden="true"
/>
<span className="sr-only">
{(this.props.language === "es") ? "Cargando datos ..." : "Loading data ..."}
</span>
</Button>{' '}
<Button variant="dark" disabled>
<Spinner
as="span"
animation="grow"
size="sm"
role="status"
aria-hidden="true"
/>
{(this.props.language === "es") ? "Cargando datos ..." : "Loading data ..."}
</Button>
</div>
}
</div>
)
}
}
module.exports.TTShooting = TTShooting;
This code returns a log when is called the first time and other times. The first time returns:
> id_team_club 1: 769
This is correct. When I send new data is called the method componentWillReceiveProps, I update the props and the state and show the id_team_club of the firs element and this is the same. The method is called twice.
> id_team_club 2: 769
> Componente recibe nuevos datos
> id_team_club 2
> Componente recibe nuevos datos
But, if I send data again, then I show the data of the second send of data in the second call to the function:
> id_team_club 2: 769
> Componente recibe nuevos datos
> **id_team_club 2: 720**
> Componente recibe nuevos datos
What am I doing wrong? How can I update the data of the table?
Edit
I have updated the code of componentWillReceiveProps and how I pass the data to the table.
componentWillReceiveProps(nextProps){
if (this.props.teams_std_stats !== nextProps.teams_std_stats) {
console.log("Vamos a modificar el state");
this.setState({
teams_std_stats: nextProps.teams_std_stats
});
}
}
<ToolkitProvider
keyField="id_team_club"
data={ this.state.teams_std_stats }
columns={ columnsTTShootingFEB }
columnToggle
>
{
props => (
<div>
<p className = "text-justify" style = {{fontSize: 12 + "pt"}}><b>Nota: </b>Para añadir o eliminar columnas en la tabla basta hacer clic sobre uno de estos botones</p>
<CustomToggleList { ...props.columnToggleProps } />
<hr />
<BootstrapTable
{ ...props.baseProps }
footerClasses = "footer-class"
defaultSorted = { sortedTTShootingFEB }
/>
</div>
)
}
</ToolkitProvider>
But, it doesn't work.
You should not change the props in react, the props of a component are read-only.
This expression is incorrect:
this.props = nextProps;
Please read this article about props props-are-read-only
Do not mutate the props in lifecycle methods. The render function will always have the updated props, you do not need to set this.props.
componentWillReceiveProps(nextProps) {
if (this.props.teams_std_stats !== nextProps.teams_std_stats) {
this.setState({
teams_std_stats: nextProps.teams_std_stats
});
}
}
Also setting this.props = props inside constructor is wrong.
constructor(props){
super(props);
this.state = {
loaded: false
};
}
(Posted a solution on behalf of the question author to move the answer to the answer space).
The problem was due to the data. Because didn't arrive correctly. These data are get it by a query to database after an event and when I assign the id of the element which fire the event this was not assigning correctly to the state.
To assign correctly the value to the state I have to do this:
async handleChange(event){
/**
* 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.
*/
event.persist();
let season = this.state.seasons.find((item) => {
return parseInt(item.id) === parseInt(event.target.value)
});
this.setState({
itemSelected: season.id,
});
}
As others have pointed the problem is related to modifying the props, but I also wanted to add that I see no need to take team_std_stats and to make it part of your component state, you can reference that straight from the props in your render function, why not just do that?
try this line
data={ this.props.teams_std_stats }
instead of
data={ this.state.teams_std_stats }
for your <ToolkitProvider /> implementation.
Hope that helps.
i just enter to "REACT " world to do my front-end off my own project and i have problem for 2 day with the function map , i get data from my back-end and i just save the id in the Cuartos array , i dont know what its my error , i try it with for loop with console.log in a function out of render and it work , but work out of the render function how i can resolve it ? i need to get all the cuarto id in the render
this is my code
class FormInterruptor extends React.Component {
constructor (){
super();
const axx={au:[]};
const Cuartos = [];
axios.get("http://localhost:5000/API/Cuartos")
.then(response => {
const a=JSON.stringify(response.data);
console.log(response.data);
axx.au=response.data;
const b=JSON.stringify(axx.au.idcuarto);
console.log("aqui estas" )
for (let i = 1; i < b.length; i=i+2)
{
Cuartos.push({idcuarto:parseInt((JSON.stringify(axx.au.idcuarto))[i])});
}
});
this.state = {
IdInterruptor: '',
IdCuarto: '',
Pin: '',
Dimmer: '',
Cuartos
};
}
onChange(e){
this.setState({
[e.target.name]:e.target.value
});
}
handleSubmit = event => {
event.preventDefault();
const Luz = {
IdInterruptor: this.state.IdInterruptor,
IdCuarto: this.state.IdCuarto,
Pin: this.state.Pin,
Dimmer: this.state.Dimmer
};
//AYUDA CON EL LUGAR DODNE SE PONDRA EL INTERRUPTOR
let config = {headers: {'Access-Control-Allow-Origin': "*"}};
axios.post('http://localhost:5000/API/Cuarto/1/Luz/add', Luz , config)
.then(res => {
//console.log(res);
console.log(res.data);
})
}
render(){
return (
<div className="App">
<header className="App-header">
<img src={process.env.PUBLIC_URL + '/Images/Escudo.png'} alt='Escudo' width='400'/>
<div className="Formulario">
<h2>
Formulario Luz
</h2>
<form onSubmit={this.handleSubmit} >
<div id='form'>
<input id="form" type="text"placeholder="ID del interruptor" value={this.state.IdInterruptor} name="IdInterruptor" onChange={this.onChange.bind(this)} />
</div>
<div id="separador">
<select id="form" name="IdCuarto" value={this.state.IdCuarto} onChange={this.onChange.bind(this)} >
</select>
</div>
<div id="separador">
<input id="form" type="text" name="Pin" placeholder="Pin" value={this.state.Pin} onChange={this.onChange.bind(this)} />
</div>
<div id="separador">
<input id="form" type="text" name="Dimmer" placeholder ="Dimmer" value={this.state.Dimmer} onChange={this.onChange.bind(this)}/>
</div>
<div >
<input type="submit" value="Submit" className="button" onChange={this.onChange}/>
</div>
</form>
</div>
<div>
{this.state.Cuartos.map(p => {
return <p > {p.idcuarto} !</p>}
)}
</div>
</header>
</div>
);
}
}
export default FormInterruptor
Update:
i change the code and i change my state in the componentDidMount and
this is my data array of Cuartos how i need to use the map function
enter image description here
First and foremost, what you should be doing is to make the HTTP request in the ComponentDidMount lifecycle hook instead of the constructor, as the purpose of the constructor is only for
Initializing local state by assigning an object to this.state. Binding
event handler methods to an instance.
constructor(props) {
super(props);
this.state = {
IdInterruptor: '',
IdCuarto: '',
Pin: '',
Dimmer: '',
Cuartos: undefined,
}
}
componentDidMount() {
let Cuartos;
axios.get("http://localhost:5000/API/Cuartos")
.then(response => {
const a=JSON.stringify(response.data);
console.log(response.data);
axx.au=response.data;
const b=JSON.stringify(axx.au.idcuarto);
console.log("aqui estas" )
for (let i = 1; i < b.length; i=i+2) {
Cuartos.push({idcuarto:parseInt((JSON.stringify(axx.au.idcuarto))[i])});
}
this.setState({ Cuartos });
});
}
Then, on your render, you should carry out a check such that you will only carry out Array.map() when the request is returned, and that Cuartos is defined, and the idcuartos array is not empty.
render() {
const { Cuartos } = this.state;
return <>
<div>
{
Cuartos && Cuartos.idcuartos.length && Cuartos.idcuartos.map(p => {
return . <p>{q}</p>
})
}
</div>
</>
}
Make your api call in componentDidMount and save your data to state and then manipulate your data before rendering.
class FormInterruptor extends React.Component {
constructor (){
super();
this.state = {
IdInterruptor: '',
IdCuarto: '',
Pin: '',
Dimmer: '',
Cuartos:[]
};
}
componentDidMount(){
axios.get("http://localhost:5000/API/Cuartos")
.then(response => this.setState({Cuartos:res.data}));
}
onChange(e){
this.setState({
[e.target.name]:e.target.value
});
}
handleSubmit = event => {
event.preventDefault();
const Luz = {
IdInterruptor: this.state.IdInterruptor,
IdCuarto: this.state.IdCuarto,
Pin: this.state.Pin,
Dimmer: this.state.Dimmer
};
//AYUDA CON EL LUGAR DODNE SE PONDRA EL INTERRUPTOR
let config = {headers: {'Access-Control-Allow-Origin': "*"}};
axios.post('http://localhost:5000/API/Cuarto/1/Luz/add', Luz , config)
.then(res => {
//console.log(res);
console.log(res.data);
})
}
render(){
return (
<div className="App">
<header className="App-header">
<img src={process.env.PUBLIC_URL + '/Images/Escudo.png'} alt='Escudo' width='400'/>
<div className="Formulario">
<h2>
Formulario Luz
</h2>
<form onSubmit={this.handleSubmit} >
<div id='form'>
<input id="form" type="text"placeholder="ID del interruptor" value={this.state.IdInterruptor} name="IdInterruptor" onChange={this.onChange.bind(this)} />
</div>
<div id="separador">
<select id="form" name="IdCuarto" value={this.state.IdCuarto} onChange={this.onChange.bind(this)} >
</select>
</div>
<div id="separador">
<input id="form" type="text" name="Pin" placeholder="Pin" value={this.state.Pin} onChange={this.onChange.bind(this)} />
</div>
<div id="separador">
<input id="form" type="text" name="Dimmer" placeholder ="Dimmer" value={this.state.Dimmer} onChange={this.onChange.bind(this)}/>
</div>
<div >
<input type="submit" value="Submit" className="button" onChange={this.onChange}/>
</div>
</form>
</div>
<div>
{this.state.Cuartos.map(p => {
return <p > {p.idcuarto} !</p>}
)}
</div>
</header>
</div>
);
}
}
export default FormInterruptor
You are making a call in the constructor which is not recommended, try doing it in componentDidMount
Javascript is asynchronous so when are making a call using axios it will not wait until the response got back it will continue to render the component, you need to update your component after you got the response
If you still want to render with your existing code, add below line after the for loop inside the axios call back
this.setState({"Cuartos": Cuartos})
I have these two select bars:
When I select an option from the first bar, I have it set up to populate this object like so:
I am trying to make it so that the options available in the second select bar populated as the contents of the needed_skills array.
So in this example, the options in the second select bar would be: "Proposal Writing", "The McKinsey 7s Framework" etc
My attempt was this:
const createInputs = () => {
return values.skills_required.map((skill, idx) => {
return (
<div className="input-group">
<select
value={skill} placeholder="Enter a skill"
onChange={e => updateSkill(e, idx)}
className="form-control">
<option>Select an option...</option>
{values.category2.needed_skills && values.category2.needed_skills.map((c, i) => (
<option
key = {i}
value={JSON.stringify(c)}>
{JSON.stringify(c)}
</option>
))}
</select>
<div className="input-group-append">
<button
className="btn btn-outline-danger mb-3"
type="button"
id="button-addon2"
onClick={() => removeSkill(idx)}>x
</button>
</div>
</div>
);
});
};
But nothing, even though when I console.log(values.category2.needed_skills) and get the array, I cant seem to map across it and return it as options in the 'select' dropdown.
Any advice/help is greatly appreciated.
#malfunction is correct, when I console log the index and elements of the loop I get nothing. How can I loop through this array of strings? My data structure is exactly like this:
const [values, setValues] = useState({
name: '',
description: '',
pitch_price: '',
categories: [],
category: '',
quantity: '',
applications: '',
business_name: '',
skills_required: [''],
category2: {
name: "",
needed_skills: [""]
},
photo: '',
created_by: '',
loading: false,
error: '',
createdProject: '',
redirectToProfile: false
});
The category2 part is where I am keeping the data. Also, I know that the data is actually there because when I console log my values.category2 object after selecting a Category - I get this:
Have you tried adding a return. i.e.
return <option key = {i}
value={JSON.stringify(c)}>
{JSON.stringify(c)}
</option>
Also, not sure if JSON.stringify is required there. It's probably not hurting though.
Ok, that wasn't it ^^^
Without knowing the structure of your data I got this working in a new create-react-app without really changing your code:
import logo from './logo.svg';
import './App.css';
import { jsxFragment } from '#babel/types';
const values = {
skills_required: [
"skill_1",
"skill_2"
],
category2: {
needed_skills: [ "Proposal Writing", "The McKinsey Framwork", "etc"],
some_other_stuff: {},
a_date: "2019-09-30"
}
}
const updateSkill = (e, idx) => {
console.log("e: ", e);
console.log("e: ", idx);
}
const removeSkill = (idx) => {
console.log("e: ", idx);
}
const createInputs = () => {
return values.skills_required.map((skill, idx) => {
return (
<div className="input-group">
<select
value={skill} placeholder="Enter a skill"
onChange={e => updateSkill(e, idx)}
className="form-control">
<option>Select an option...</option>
{values.category2.needed_skills && values.category2.needed_skills.map((c, i) => (
<option
key = {i}
value={JSON.stringify(c)}>
{JSON.stringify(c)}
</option>
))}
</select>
<div className="input-group-append">
<button
className="btn btn-outline-danger mb-3"
type="button"
id="button-addon2"
onClick={() => removeSkill(idx)}>x
</button>
</div>
</div>
);
});
};
function App() {
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<p>
Edit <code>src/App.js</code> and save to reload.
</p>
<a
className="App-link"
href="https://reactjs.org"
target="_blank"
rel="noopener noreferrer"
>
Learn React
</a>
<jsxFragment>
{ createInputs()}
</jsxFragment>
</header>
</div>
);
}
export default App;
Is your data structure similar to that? I'd say that the issue might be with the data structure possibly looping through and getting nothing.
If you're not sure you can always add a console.log in here:
<option>Select an option...</option>
{ values.category2.needed_skills
&& values.category2.needed_skills.map((c, i) => {
console.log("c", c);
console.log("i", i);
return ( <option
key = {i}
value={JSON.stringify(c)}>
{JSON.stringify(c)}
</option>)
}
)
}
The initial return didn't work because the curly braces weren't there.
The only other thing I can think of is making your array it's own variable. i.e. let needed_skills = values.category2.needed_skills;
I hope one of those things helps.
Using React.Js, I created a delete function to delete an item from a table. the delete is working fine but what I want to do is that after deleting I want the tables to be dynamically updated to show only the items left. Now after the delete I have to refresh manually the page or go to another page and comeback to see the items left after the delete
This is the code built so far :
import React, { Component } from "react";
import { Card, Button, Select,/* message, */ Form, Tooltip } from "antd";
import extraitMP3 from "./data";
import { arrayMove, SortableHandle } from "react-sortable-hoc";
import ContainerHeader from "components/ContainerHeader/index";
import { getExtraitMp3, hideMessageUpdate, showUpdateLoader, updateMp3Visibilite } from "appRedux/actions/Comedien";
import { deleteMp3Request } from "../../../appRedux/services/extraitMp3Service"
import { connect } from "react-redux";
import { NotificationContainer, NotificationManager } from "react-notifications";
import { userSignOut } from "appRedux/actions/Auth";
import { displayIcon } from '../../../util/Icon.js';
import CircularProgress from "components/CircularProgress";
import { Modal } from "antd";
const extraitMP32 = [extraitMP3];
const confirm = Modal.confirm;
const Option = Select.Option;
const DragHandle = SortableHandle(() =>
<span className="gx-draggable-icon gx-pt-2">
<i className="icon icon-menu" style={{ fontSize: 25 }} />
</span>);
class ListExtrait extends Component {
onSortEnd = ({ oldIndex, newIndex }) => {
this.setState({
extraitMP3: arrayMove(this.state.extraitMP3, oldIndex, newIndex),
});
};
constructor() {
super();
this.state = {
extraitMP3: extraitMP32[0],
nombreMP3: {
rechercheExtraits: 0,
recherchePossible: 0,
extraitFiche: 0,
extraitFichePossible: '',
extraitArchives: 0,
extraitArchivesPossible: '',
},
loader: false,
}
}
componentDidMount() {
this.props.getExtraitMp3();
}
componentDidUpdate() {
}
static getDerivedStateFromProps(nextProps, prevState,/* nextProps2,prevState2 */) {
if (nextProps.extraitMP3 !== prevState.extraitMP3 && nextProps.extraitMP3) {
return { extraitMP3: nextProps.extraitMP3 };
}
else return null;
}
showDeleteConfirmation(value, id, index, thisHandler) {
confirm({
title: 'Voulez vous supprimer cette audio ?',
content: '',
okText: 'Oui, je confirme',
okType: 'danger',
cancelText: 'Non',
onOk() {
deleteMp3Request(id);
const { extraitMP3 } = thisHandler.state;
Object.keys(extraitMP3).splice(index, 1);
NotificationManager.success("le fichier audio est supprimé avec succès !", "");
},
onCancel() {
},
});
}
handleSubmit = (e) => {
e.preventDefault();
this.props.form.validateFields((err, values) => {
if (!err) {
this.props.showUpdateLoader();
this.props.updateMp3Visibilite(values);
}
});
};
render() {
const { loader, extraitMP3 } = this.state;
const selectOptions = new Map([
[1, "Visible dans la recherche et sur ma fiche"],
[2, "Visible sur ma fiche uniquement"],
[3, "Masqué"],
]);
console.log('extraitMP3', extraitMP3)
function handleChangeSelect(value) {
console.log(`selected ${value}`);
}
return (
<div>
{loader ? <CircularProgress className="gx-loader-400" /> : Object.keys(extraitMP3).map((ids, index) => {
return (
<Card>
<li key={ids}>
<Card styleName="gx-card-list icon icon-data-display gx-mr-2 gx-text-blue gx-fs-xl">
<div className="gx-media-body">
{extraitMP3[ids].Typenom}
{extraitMP3[ids].TypeIcon != null &&
displayIcon(extraitMP3[ids].TypeIcon)
}
</div>
{Object.keys(extraitMP3[ids].TypeMp3List).map(idJson => {
return (
<div className="gx-main-content gx-mb-4">
<ContainerHeader match={this.props.match} />
<div className="gx-contact-item gx-dragndrop-item">
<DragHandle />
<div className="gx-col gx-job-title ">
{extraitMP3[ids].TypeMp3List[idJson].intitule}
</div>
{extraitMP3[ids].TypeMp3List[idJson].interpretation1Icon !== '' &&
<Tooltip title={extraitMP3[ids].TypeMp3List[idJson].interpretation1Nom}>
{displayIcon(extraitMP3[ids].TypeMp3List[idJson].interpretation1Icon)}
</Tooltip>
}
{extraitMP3[ids].TypeMp3List[idJson].interpretation2Icon !== '' &&
<Tooltip title={extraitMP3[ids].TypeMp3List[idJson].interpretation2Nom}>
{displayIcon(extraitMP3[ids].TypeMp3List[idJson].interpretation2Icon)}
</Tooltip>
}
{extraitMP3[ids].TypeMp3List[idJson].interpretation3Icon !== '' &&
<Tooltip title={extraitMP3[ids].TypeMp3List[idJson].interpretation3Nom}>
{displayIcon(extraitMP3[ids].TypeMp3List[idJson].interpretation3Icon)}
</Tooltip>
}
{extraitMP3[ids].TypeMp3List[idJson].langueIcon !== '' &&
<div className="gx-col gx-job-title gx-d-sm-flex gx-text-truncate gx-px-8">
<Tooltip title={extraitMP3[ids].TypeMp3List[idJson].langueNom}>
<i className={`flag flag-24 gx-mr-2 ${extraitMP3[ids].TypeMp3List[idJson].langueIcon}`} />
</Tooltip>
</div>
}
<div className="gx-col gx-job-title gx-d-sm-flex gx-text-truncate gx-px-8">
<Select
showSearch
style={{ width: '100%' }}
placeholder="Selection la choix de votre numéro de téléphone "
optionFilterProp="children"
onChange={handleChangeSelect}
defaultValue={selectOptions.get(extraitMP3[ids].TypeMp3List[idJson].visibilite)}
filterOption={(input, Option) => Option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0}
>
{[...selectOptions].map(([value, label]) => <Option value={value}> {label} </Option>)}
</Select>
</div>
<div className="gx-col gx-job-title gx-d-sm-flex gx-text-truncate gx-px-8">
<i className="icon icon-edit gx-fs-xl gx-text-gris" />
</div>
<div className="gx-col gx-job-title gx-d-sm-flex gx-text-truncate gx-px-8">
<span className="gx-pointer">
<i className="icon icon-trash gx-pointer gx-text-danger gx-fs-xxl"
id={extraitMP3[ids].TypeMp3List[idJson].id}
onClick={e => this.showDeleteConfirmation(e.target.value, extraitMP3[ids].TypeMp3List[idJson].id, index, this)} />
</span>
</div>
</div>
</div>
)
})}
<NotificationContainer />
<Button type="primary" htmlType="submit" labelCol={{ xs: 24, sm: 5 }} wrapperCol={{ xs: 24, sm: 12 }}>
Enregistrer
</Button>
</Card>
</li>
</Card>
)
})}</div>
)
}
}
const VisibiliteFormMp3 = Form.create()(ListExtrait);
const mapStateToProps = ({ comedien }) => {
const {
extraitMP3,
alertMessageUpdate,
showMessageUpdate
} = comedien;
return {
extraitMP3,
alertMessageUpdate,
showMessageUpdate
}
};
export default connect(
mapStateToProps,
{
userSignOut,
getExtraitMp3,
hideMessageUpdate,
showUpdateLoader,
updateMp3Visibilite
})(VisibiliteFormMp3);
extraitMP3 is an object of objects that's why I used Object.keys(extraitMP3)
I didn't know how to update the state correctly.
this is the view :
You should put your data in state and then change the state. After changing the state the page automatically re-rendered and changed data of your state will be shown.
So in your delete function simply delete your chosen data and give your remaining data to your state.
Hope this helps, feel free to ask questions if I couldn't explain myself clearly.
I believe you can do this by calling something like and then just call this from within your delete
refreshMp3(){
this.setState({getExtraitMp3: !this.state.getExtraitMp3});}
One of the ideas of React is to make the functionality you ask for simple to implement and it would update automatically. I'm going to abstract a bit from your example. Think about your data in terms of what updates along with the UI. This way we can simplify your component. You have some items that you put in a table. Each item is a row and can be inside an array. We put that array in the state.
class ListExtrait extends Component {
constructor() {
super();
this.state = {
rowsForTable: [...],
somethingElse...
}
...
Then in the JSX in the render method you can render the table rows using map:
rowsForTable.map(item => <div/li/whatever>{item.name or something else}</div>
This way whenever an item is gone from rowsForTable the component will automatically update it's view and the table rows will be up to date.
You can simply call the function while clicking the delete button say deleteHandler. On that function call the api you have made to delete the item and then after successfull delete again call the api that will show the item from database after certain time interval.
Code:
import React, { Component } from 'react'
export default class show_schedule extends Component {
render() {
state={
}
show_item_after_delete=()=>{
setTimeout(()=>{
axios.get(`http://127.0.0.1:8000/account/api/show_item/`).then(res=>{
console.log('delete schedule data ',res.data)
})
},500)
}
deleteHandler=()=>{
axios.delete(`http://127.0.0.1:8000/account/api/delete_item/${id}`).then(res=>{
console.log(res.data)
})
this.show_item_after_delete()
}
return (
<div>
<button onClick={this.deleteHandler}>Delete</button>
</div>
)
}
}