Home > OS >  d3 react.js on click of d3 tree node text this.props.history.push gives error "Cannot read prop
d3 react.js on click of d3 tree node text this.props.history.push gives error "Cannot read prop

Time:04-28

With the help of d3 and react.js, I am able to create d3 hierarchy tree

enter image description here

What I want to achieve is, On click of each node text (eg John, Luke, ...) it should route to detail page of each clicked text.

nodes
    .append("text")
    .attr("font-size", "17px")
    .attr("text-anchor", "start")
    .text(function (d) {
        return `${d.data.name}`
    })
    .on("click", function (event, d) {
        this.props.history.push(`/detail/${d.id}`);
});

constructor

constructor(props) {
    super(props);
    console.log(this.props)                  // there is history in props
    this.state = {
      isClicked: ""
      };
    this.geGraph = this.getGraph.bind(this);  // function where graph code presents

after clicking the node text. I getting error.

Uncaught TypeError: Cannot read properties of undefined (reading 'history')

Also when I debug on line this.props.history.push, there is no props in this .

Tried to follow this How to use React Router with d3.js Graphs to redirect to another screen . still got the same issue. and when i try to go for arrow function

.on("click", (event, d) => this.props.history.push(`/detail/${d.id}`))

it gives issue for props this time Uncaught TypeError: Cannot read properties of undefined (reading 'props')

I have added history in <Route history={createBrowserHistory()}/> as well import { createBrowserHistory } from "history";. and did export default withRouter(MyGraph) imported from import { withRouter } from 'react-router-dom';.

I m using router version "react-router-dom": "^4.3.1" and class based components.

How do I resolve this issue.

Thanks in advance!

CodePudding user response:

Your are using this on different scope, its scope is functional now, its better to define a function for click inside component and call it on click event.

Or you can store this value in another variable inside nodes creation scope and use it from that.

CodePudding user response:

According to the javascript DOM API documentation, the reference to this will be the DOM element you will click on.

nodes
    .append("text")
    .attr("font-size", "17px")
    .attr("text-anchor", "start")
    .text(function (d) {
        return `${d.data.name}`
    })
    .on("click", function (event, d) {
        // try console.log here
        console.log(this);   // <--- most likely be a DOM element you clicked
        this.props.history.push(`/detail/${d.id}`); // <--- therefore this.props does not exist
});

Solution 1

use either Javascript arrow function:

.on("click", (event, d) => {
        console.log(this);   // <--- this should refer to the parent object
        this.props.history.push(`/detail/${d.id}`);
});

Solution 2

or bind the click event handler in the constructor with this

constructor(props) {
    super(props);
    console.log(this.props)                  
    this.state = {
      isClicked: ""
      };
    this.geGraph = this.getGraph.bind(this);
    this.nodeClickHandler = this.nodeClickHandler.bind(this);
}

function nodeClickHandler (event, d) {
    this.props.history.push(`/detail/${d.id}`);
}
nodes
    .append("text")
    .attr("font-size", "17px")
    .attr("text-anchor", "start")
    .text(function (d) {
        return `${d.data.name}`
    })
    .on("click", this.nodeClickHandler);
  • Related