Reputation: 7656
Here is my current code
class cart extends Component {
state = { loading: [] };
addToCart = (e, id) => {
let loading = this.state.loading.slice();
loading[e] = true;
this.setState({
loading,
})
};
render() {
const { data } = this.props;
return (
<div>
{data.map(catering => {
const { menus } = catering;
return (
<Row>
{menus.map(menu => (
<Col xs={12} md={12} lg={6} key={menu.id} className="m-bottom-15">
<Card style={{ height: '165px', border: 0, overflow: 'hidden' }}>
<CardActions>
<LoadingButton
className="button small primary pull-right"
loading={thi.state.loading || false}
onClick={e => this.addToCart(e, menu.id)}
>
<MdAdd size={18} color={white} />
<span className="font-14 font-400">Add to cart</span>
</LoadingButton>
</CardActions>
</Card>
</Col>
))}
</Row>
);
}
}
There will be around 20 button when the map
function is done.
What I want to achieve is: every time users click add to cart
button, I will call the ajax to save the cart and show loading for the specific clicked button.
After ajax is done, return the state back to normal.
On my current code I haven't put my ajax call yet, I still want to make sure the loading button work on press. Right now its not working.
How can I achieve this?
Thanks.
Upvotes: 2
Views: 7191
Reputation: 3922
for the hooks guys this is what I did
const [isLoading, setIsLoading] = useState([]);
<button
type="button"
disabled={isLoading[item.username]}
className="btn btn-success btn-rounded btn-sm my-0"
onClick={()=>activateOrDeactivate( item.activated,item.username)}
> {isLoading[item.username] && <i className="fa fa-circle-o-notch fa-spin"></i>}
{isLoading[item.username]&& <span> Activating...</span>}
{!isLoading[item.username]&& <span>Activate</span>}</button>
const activateOrDeactivate = (valTrueOrFalse,newusername) => {
let loading = isLoading.slice();
loading[newusername] = true;
setIsLoading(loading)
let config = {
headers: {
Authorization: "Bearer " + state.token
},
};
api.post(
"process-activation",
{
activated: !valTrueOrFalse,
username:newusername
},
config
).then(
response => {
getAllUsers()
let loading = isLoading.slice();
loading[newusername] = false;
setIsLoading(loading)
Upvotes: 0
Reputation: 104459
Instead of maintaining bool
in loading array
, maintain the menu ids, whenever Add button is clicked, push the id of that item into loading array
. When generating the card check whether loading array
have that id
or not, if yes then show loading otherwise show the card.
Write it like this:
class cart extends Component {
state = { loading: []};
addToCart = (e, id) => {
let loading = this.state.loading.slice();
loading.push(id);
this.setState({
loading
})
};
render() {
const { data } = this.props;
return (
<div>
{data.map((catering,i) => {
const { menus } = catering;
return (
<Row>
{menus.map(menu => {
return this.state.loading.indexOf(menu.id) >= 0 ?
<Col xs={12} md={12} lg={6} key={menu.id} className="m-bottom-15">
<Card style={{ height: '165px', border: 0, overflow: 'hidden' }}>
<CardActions>
<LoadingButton
className="button small primary pull-right"
loading={thi.state.loading || false}
onClick={e => this.addToCart(e, menu.id)}
>
<MdAdd size={18} color={white} />
<span className="font-14 font-400">Add to cart</span>
</LoadingButton>
</CardActions>
</Card>
</Col>
:
/*Loading icon*/
})}
</Row>
)
})}
)
}
}
Upvotes: 0
Reputation: 2820
There is some error in your addToCart method. You should use id as index of loading and set loading array to state as this:
addToCart = (e, id) => {
let loading = this.state.loading.slice();
loading[id] = true;
this.setState({
loading: loading
});
};
Also, in your render method, change this.state.loading to this.state.loading[menu.id]:
<LoadingButton
className="button small primary pull-right"
loading={this.state.loading[menu.id] || false}
onClick={e => this.addToCart(e, menu.id)}
>
When ajax call is done, you just call setState function which sets loading array values to false in callback method.
Upvotes: 5