0

In my render function,i am dynamcially dispalying a set of products with details such as their image,price,quantity increase/decrease and the amount which the user has already bought.Now i would like to attach a function on onCLick with parameters so that i can delete this product and hide it from the rendered HTML page.Here is what i have tried so far.

What happens is that when the page gets rendered,the onClick functions get automaticaly called which is something i don't want.

Here is the code for the same.

import React from 'react'
import App from './App'
import Cookies from 'universal-cookie'
import './view_cart.css'
import {ToastContainer, toast,style} from 'react-toastify'

class View_cart extends React.Component
{
  constructor(props)
  {
    super(props);
    this.state={item_list:{},"total_items_price":'',product_count:''}
    this.view_cart_details=this.view_cart_details.bind(this)
    this.delete_item_cart=this.delete_item_cart.bind(this)
  }

  registeration_notification(value_to_render)
  {
    toast(value_to_render,
      {
        //position: toast.POSITION.BOTTOM_CENTER,
        autoClose: 3000,
      }
    );
  }

  product_state(e)
  {
    this.setState({"product_count":e.target.value})
    //console.log(this.state.product_count)
  }

  display_cart()
  {
    //console.log(Object.keys(this.state.item_list))
    const mapping = Object.keys(this.state.item_list).map((item,id) =>
    {
      console.log(this.state.item_list[item]['image_path'])
      var location = require('./Images/'.concat(this.state.item_list[item]['image_path']))
      //console.log(location)
      return (
        <div>
          <div class="container">
            <table id="cart" class="table table-hover table-condensed">
              <thead>
                <tr>
                  <th style={{width:50}}>Product</th>
                  <th style={{width:10}}>Price</th>
                  <th style={{width:8}}>Quantity</th>
                  <th style={{width:22}} class="text-center">Subtotal</th>
                  <th style={{width:10}}></th>
                </tr>
              </thead>
              <tbody>
                <tr>
                  <td data-th="Product">
                    <div class="row">
                      <div class="col-sm-2 hidden-xs"><img src={location} alt="..." class="img-responsive"/></div>
                      <div class="col-sm-8">
                        <h4 class="nomargin">{this.state.item_list[item]["Name"]} {'by '.concat(this.state.item_list[item]["manufacturer"])}</h4>
                      </div>
                    </div>
                  </td>
                  <td data-th="Price">{this.state.item_list[item]["original_price"]}</td>
                  <td data-th="Quantity">
                    <input type="number" class="form-control text-center" value="1"/>
                  </td>
                  <td data-th="Subtotal" class="text-center">{this.state.item_list[item]['price']}</td>
                  <td class="actions" data-th="">
                    <button class="btn btn-danger btn-sm" onClick={this.delete_item_cart(this.state.item_list[item]["Name"],this.state.item_list[item]["manufacturer"])}><i class="fa fa-trash-o"></i></button>
                  </td>
                </tr>
              </tbody>
            </table>
          </div>
        </div>
          )
    })
  return mapping
}

  sample_string()
  {
    console.log("ONCLICK WORKING")
  }
  sample_cookie_output()
  {
    const test_cookie_testing = new Cookies();

    var auth_string='Token '
    console.log((auth_string.concat(test_cookie_testing.get('Authorization'))),typeof((auth_string.concat(test_cookie_testing.get('Authorization')))))
    return (auth_string.concat(test_cookie_testing.get('Authorization')))
  }

  delete_item_cart(product_name_delete,manufacturer_name)
  {
    fetch('http://127.0.0.1:8000/delete_item_cart/',
    {
      method:"POST",
      headers:
      {
      'Content-Type':"application/json",
      "Accept":"application/json",
      "Authorization":this.sample_cookie_output()
    },
      body:JSON.stringify({"product_name":product_name_delete,"manufacturer":manufacturer_name})

  })
  .then(something =>something.json())
  .then(findResponse =>
    {
      console.log(findResponse,typeof(findResponse))
      if((Object.keys(findResponse).length)===1 && (Object.keys(findResponse).includes("Data Deletion")))
      {
        //console.log("A user with this name already exists.")
        this.registeration_notification("The Product has been removed from the cart")
      }
    }
  )
  }

  view_cart_details()
  {
    fetch('http://127.0.0.1:8000/view_cart/',
    {
      method:"GET",
      headers:
      {
        'Content-Type':"application/json",
      "Accept":"application/json",
      "Authorization":this.sample_cookie_output()
    },
  })
.then(something =>something.json())
.then(findResponse =>
  {
    console.log(findResponse)
    this.setState({"item_list":findResponse[0],"total_items_price":findResponse[1]})
  }

)
  }

componentDidMount(){
  this.view_cart_details()
}

render(){
  return (
    <div>
      <App/>
      {this.display_cart()}
      <button onClick={this.delete_item_cart}>Test Button</button>
      <ToastContainer/>
    </div>
  )
}
}

export default View_cart

2 Answers 2

2

The problem here is that you call the this.delete_item_cart at render time.

So when you write

onClick={
  this.delete_item_cart(
    this.state.item_list[item]["Name"],
    this.state.item_list[item]["manufacturer"]
  )
}

the curly braces represent an expression which, here, is a function call which return value will be used as the onClick prop value.

What you want here is not the return value but an actual function to pas as a prop so what are the options here ?

For example, if you wrote

onClick={this.delete_item_cart}

It would "work" because you are passing a function as the expression, not its return value.

An obvious solution here is to wrap the function in another function like so:

onClick={() =>
  this.delete_item_cart(
    this.state.item_list[item]["Name"],
    this.state.item_list[item]["manufacturer"]
  )
}

What have we done here?

We created an anonymous function which returns the function we want to call with its arguments. So when clicking, the this.delete_item_cart function will be called with specified arguments.

This arrow notation can be difficult to understand sometimes so this is what it would look like using ES5 functions :

onClick={function () {
  return this.delete_item_cart(
    this.state.item_list[item]["Name"],
    this.state.item_list[item]["manufacturer"]
  )
}}

I hope this helps you understand and unstuck you on this issue.

Sign up to request clarification or add additional context in comments.

Comments

2

Change

onClick={this.delete_item_cart(this.state.item_list[item]["Name"],this.state.item_list[item]["manufacturer"])}

to

onClick={() => this.delete_item_cart(this.state.item_list[item]["Name"],this.state.item_list[item]["manufacturer"])}

Documentation https://reactjs.org/docs/handling-events.html

3 Comments

But the Delete_item_cart function accepts this parameters and calls an API to delete the item.So by using the syntax that you have mentioned,will the call still work?
In fact, with the first syntax, the method is called when the render() method is called. Here the arrow function wraps this so it is called on actual clicking.
With JSX you pass a function as the event handler if you refer to a method with () onClick={() => do()} without () onClick={do}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.