Steven Collins
Steven Collins

Reputation: 383

React - pass id from state on client to axios.get on express server

I am trying to pass the id from my React app to axios.get on the server side (Express) so I get this:

    //get
app.get('/api/siteDashboard', (req, res, next) => {
    axios.get('https://****/api/site?id=3d5a6a8a-60d4-4488-1401-08d74bf02cbf')
    .then(response => res.json(response.data))
        .catch(err => next(err));
})

On the client side I have a datatable and each row has a link to a new page. The data for the datatable is coming from the api. I want to be able to click the link for a specific row and grab its ID from the api and open the new page based on this ID.

    <Link to="/Sites/SiteDashboard">
        <MDBIcon icon="fa fa-external-link-alt" size="lg" className='green-text cursor-pointer' />
    </Link>

I am fetching the route from the server like this in my client side React app..

componentDidMount() {

this.setState({ loading: true });

//const { match: { params }} =this.props

//fetch(`/api/site/?id=${this.state.siteDashboard}`)
fetch(`/api/siteDashboard`)
    .then(res => res.json())
    .then(data => {
        this.setState({
            siteData: data,
            loading: false,
        })
    })

So basically, rather than hard coding the id into the axios.get request, I need to dynamically grab this from the link on the client side. Im not sure if I am approaching this the right way so any advice appreciated. Thanks.

React code...

import React from 'react'
import { Redirect } from "react-router-dom";
import styled from 'styled-components';
import DataTable, { memoize } from 'react-data-table-component'
import Moment from 'react-moment';
import Spinner from '../../Spinner'
import { BrowserRouter as Route, Link } from "react-router-dom";
import { MDBContainer, MDBCard, MDBCardBody, MDBRow, MDBCol, MDBBtn, MDBIcon } from 'mdbreact';

//import SiteDashboard from './SiteDashboard';
import SiteAdd from './SiteAdd'
import SiteDashboard from './SiteDashboard'

const TextField = styled.input`
  height: 32px;
  width: 300px;
  border-radius: 3px;
  border: 1px solid #e5e5e5;
  padding: 16px;

  &:hover {
    cursor: pointer;
  }
`;


const Filter = ({ onFilter }) => (
    <TextField id="search" type="search" role="search" placeholder="Search Title" onChange={e => onFilter(e.target.value)} />
);

const columns = memoize(clickHandler => [
    {
        name: 'Online',
        selector: 'cloudAccessEnabled',
        sortable: true,
        minWidth: '10px',
        center: true,
        cell: row => (
            <MDBIcon icon="circle"
                className={row.cloudAccessEnabled === true ? 'green-text' : 'red-text'} />
        )
    },
    {
        name: 'Site Ref.',
        selector: 'siteRef',
        sortable: true,
        wrap: true,
        minWidth: '40px',
    },
    {
        name: 'Name',
        selector: 'name',
        sortable: true,
        wrap: true,
        minWidth: '80px',
    },
    {
        name: 'Address Type',
        sortable: true,
        wrap: true,
        minWidth: '100px',
        //dont show this column
        hide: 6000,
        cell: row => (
            <div>
                {row.addresses && row.addresses.map(
                    ({ addressType, id }) => (
                        <div key={id}>
                            <ul>
                                <li>{addressType}</li>
                            </ul>
                        </div>
                    ))}
            </div>
        )
    },
    {
        name: 'Address',
        selector: 'address',
        wrap: true,
        minWidth: '100px',
        cell: row => (
            <div>
                {row.addresses && row.addresses.map(
                    ({ addressType, address1, address2, city, county, postCode, country, id }) => (
                        <div key={id}>
                            <ul>
                                <li><strong>{addressType}</strong></li>
                                <li>{address1}</li>
                                <li>{address2}</li>
                                <li>{city}</li>
                                <li>{county}</li>
                                <li>{postCode}</li>
                                <li>{country}</li>
                            </ul>
                        </div>
                    ))}
            </div>
        )
    },
    {
        name: 'Control Panel',
        selector: 'controlPanel',
        minWidth: '70px',
        wrap: true,
        cell: row => (
            <div>
                {(row.controlpanel == null) ?
                    <div>no CP assigned</div> : row.controlpanel}
            </div>
        )
    },
    {
        name: 'Last Maintenance',
        selector: 'lastMaintenance',
        defaultSortAsc: true,
        sortable: true,
        wrap: true,
        minWidth: '100px',
        //hide: 1030,
        cell: row => (
            <Moment format="DD/MM/YYYY HH:mm">{row.lastMaintenance}</Moment>
        )
    },
    {
        name: 'Next Maintenance',
        selector: 'nextMaintenance',
        sortable: true,
        wrap: true,
        minWidth: '100px',
        //hide: 1030,
        cell: row => (
            <Moment format="DD/MM/YYYY HH:mm">{row.nextMaintenance}</Moment>
        )
    },
    {
        name: 'Latest Result',
        selector: 'latestResult',
        sortable: true,
        minWidth: '90px',
    },
    {
        name: 'Site Dashboard',
        minWidth: '47px',
        center: true,
        cell: row => (
            <MDBIcon onClick={clickHandler} icon="fa fa-external-link-alt" size="lg" className='green-text cursor-pointer' />
        )
    },
]);

class Sites extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            loading: false,
            sites: [],
            toggledClearRows: false
        }
    }

    // handler for link to Site Dashboard
    handleButtonClick = () => {
        console.log("clicked");
        //<Redirect to={"/Sites/SiteDashboard" + this.state.sites.id} />
    };

    componentDidMount() {

        this.setState({ loading: true });

        //const { match: { params } } =this.props

        fetch('/api/site')
            .then(res => res.json())
            .then(site => {
                this.setState({
                    sites: site.array,
                    //cahnge to true to debug
                    loading: false
                });
                console.log(this.state.sites)
            })
            .catch(error => {
                if (error.response) {
                    console.log(error.responderEnd);
                }
            });
    }

    render() {

        // The row data is composed into your custom expandable component via the data prop
        const ExpandedSection = ({ data }) =>
            <MDBContainer fluid>
                <p className="small mt-2">
                    <strong>Notes: </strong>
                    {data.notes}
                </p>
            </MDBContainer>

        //Spinner
        const CustomLoader = () => (<div><Spinner /></div>);
        const { loading } = this.state;

        return (

            <div>
                <MDBCard className="full-width sites-dt">
                    <MDBCardBody>
                        <MDBRow className="my-4 ml-1">
                            <MDBCol sm="12" md="4" className="text-center text-md-left">
                                <h3>Sites</h3>
                            </MDBCol>
                            <MDBCol sm="12" md="8" className="text-center text-md-right">
                                <Route path="/Sites/SiteAdd" component={SiteAdd} />
                                <Link to={`/Sites/SiteAdd`}>
                                    <MDBBtn outline color="primary">
                                        <MDBIcon icon="plus" /> Add a new Site
                            </MDBBtn>
                                </Link>
                            </MDBCol>
                        </MDBRow>
                        <Link to={`/Sites/SiteDashboard`}>temp link to Site Dashboard <MDBIcon icon="fa fa-external-link-alt" size="lg" className='green-text' />
                        </Link>
                        <MDBRow>
                            <MDBCol>
                                <DataTable className="responsive-table site-headers pagination-align-left"
                                    columns={columns(this.handleButtonClick)}
                                    data={this.state.sites}
                                    defaultSortField="siteRef"
                                    defaultSortAsc={false}
                                    subHeader
                                    //subHeaderComponent={<Filter onFilter={value => setFilterText(value)} />}
                                    compact
                                    pagination
                                    highlightOnHover
                                    expandableRows
                                    expandableRowsComponent={<ExpandedSection />}
                                    progressPending={loading}
                                    progressComponent={<CustomLoader />}
                                />
                            </MDBCol>
                        </MDBRow>
                    </MDBCardBody>
                </MDBCard>

            </div>
        );
    }
}


export default Sites

enter image description here

Upvotes: 0

Views: 9918

Answers (2)

Udit
Udit

Reputation: 393

you can a write a separate function for the API call from where you are getting ids/routes:

 ComponentDidMount(){
      app.get('/api/siteDashboard', (req, res, next) => {
            // your call

        })
    }

Here you have to make a change in route as well to add another route on the client-side, so to make URL for every item in the table.

<Route path='/site/siteDashboard/:id' component={youComponent} />
      //youComponent which shows the details of the item

and where you are mapping your items in the table, just wrap each item with

<Link to=`/sites/siteDashboard/${this.state.id} />

Now when on the component where you are showing item details :

var id = props.match.params.id; // this will get your id from URL
or 
var id = this.props.match.params.id;
axios.get('https://pathc/id?=${id}') //like this

and pass it to the API call to get its data.

Upvotes: 2

Horatiu Jeflea
Horatiu Jeflea

Reputation: 7414

Can you share the React code also? Will edit my answer with appropriate code

What you need to do is:

  • Fetch all table data from the server side
  • Create a React component for the table which will hold multiple table entries (another React component), each one with a id prop
  • onClick handler for each button of each table entry
  • onClick will he handled by the table item component which has the id prop, sending an axios request to fetch the data
  • change the state once axios has returned the item's data

Upvotes: 0

Related Questions