1

The problem: How do I updated a dropdown menu after selection?

Sorry if this question is simple but I have been trying many different ways to make it work. I am building a boat visualizer using AISHub APIs. After inquiring the APIs I am able to obtain a json file with the vessels I am interested in and inject these vessels inside a table and show their marker on a google-map. Now some vessel do some functions, others do something else, and I am trying to filter that using a dropdown menu.

Below the most important part of the code:

GoogleMap.js:

class BoatMap extends Component {
    constructor(props) {
        super(props);
        this.state = {
            buttonEnabled: true,
            buttonClickedAt: null,
            progress: 0,
            ships: []
        };
        this.updateRequest = this.updateRequest.bind(this);
        this.countDownInterval = null;
    }

    componentDidMount() {
        this.countDownInterval = setInterval(() => {
            if (!this.state.buttonClickedAt) return;
            const date = new Date();
            const diff = Math.floor((date.getTime() - this.state.buttonClickedAt.getTime()) / 1000);

            if (diff < 90) {
                this.setState({
                    progress: diff,
                    buttonEnabled: false
                });
            } else {
                this.setState({
                    progress: 0,
                    buttonClickedAt: null,
                    buttonEnabled: true
                });
            }
        }, 500);
    }

    componentWillUnmount() {
        clearInterval(this.countdownInterval);
    }

    async updateRequest() {
        const url = 'http://localhost:3001/hello';
        console.log(url);
        const fetchingData = await fetch(url);
        const ships = await fetchingData.json();

        console.log(ships);

        this.setState({
            buttonEnabled: false,
            buttonClickedAt: new Date(),
            progress: 0,
            ships
        });
        setTimeout(() => {
            this.setState({ buttonEnabled: true });
        });
    }

    render() {
        return (
            <div className="google-map">
                <GoogleMapReact
                    bootstrapURLKeys={{ key: 'My_KEY' }}
                    center={{
                        lat: 42.4,
                        lng: -71.1
                    }}
                    zoom={8}
                >
// This will render the customized marker on Google-Map
                    {this.state.ships.map((ship) => (
                        <Ship ship={ship} key={ship.CALLSIGN} lat={ship.LATITUDE} lng={ship.LONGITUDE} />
                    ))}
// This is the dropdown I am trying to update
                    <select className="combo-companies">
                        <option value="All">All</option>
                        <option value="research">research</option>
                        <option value="exploration">exploration</option>
                        <option value="navigation">navigation</option>
                        <option value="drilling">drilling</option>
                    </select>
                </GoogleMapReact>
            </div>
        );
    }
}

ShipTracker.js

const Ship = ({ ship }) => {
    const shipName = ship.NAME;
    const company = shipCompanyMap[shipName];

    const shipImage = companyImageMap[company];
    return (
        <div>
            {/* Render shipImage image */}
            <img src={shipImage} alt="Logo" />
        </div>
    );
};
export { Ship };

const ShipTracker = ({ ships }) => {
    const handleRowClick = (rowValue) => {
        console.log(rowValue);
    };
    return (
        <div className="ship-tracker">
            <Table className="flags-table" responsive hover>
                <thead>
                    <tr>
                        <th>#</th>
                        <th>Name</th>
                        <th>Callsign</th>
                        <th>Heading</th>
                        <th>SOG</th>
                        <th>IMO</th>
                        <th>MMSI</th>
                        <th>Longitude</th>
                        <th>Latitudee</th>
                    </tr>
                </thead>
                <tbody>
                    {ships.map((ship, index) => {
                        const { IMO, NAME, CALLSIGN, HEADING, SOG, MMSI, LONGITUDE, LATITUDE } = ship;
                        const cells = [ NAME, CALLSIGN, HEADING, SOG, IMO, MMSI, LONGITUDE, LATITUDE ];
                        return (
                            <tr onClick={() => handleRowClick(ship)} key={index}>
                                <th scope="row">{index}</th>
                                {cells.map((cell) => <td>{cell}</td>)}
                            </tr>
                        );
                    })}
                </tbody>
            </Table>
        </div>
    );
};

export default ShipTracker;

What I have done so far:

1) After investigating I came across this source which was useful to understand the concept behind the choice. That question remained unanswered and was wondering if the functions componentWillMount and componentWillReceiveProps will have to be implemented or if there is an additional way.

2) This post was useful too, but made me a bit confused as it seems that there need to be setState as an additional function for the implementation.

3) It seems from here that a response has to be provided within a handler function. Although useful I think this post is sum of point 1) + 2).

I know this is a simple example but I was trying to understand the basic concept on how to update a simple dropdown before passing to something more intermediate or advanced. Thanks for pointing in the right direction for solving this problem.

10
  • Hello. "This is the dropdown I am trying to update": what do you want to have in this dropdown? The list of the ships? Commented Feb 11, 2020 at 16:44
  • Hello, yes correct, together with their logo. Commented Feb 11, 2020 at 16:47
  • I just want to fully understand your question. Why do you already have options in your select element? Commented Feb 11, 2020 at 16:51
  • I already have choices because I already know their function. I have a vessel_data.js which is a template file that looks like this. And from there I can say the type of the vessel. In the image for example that one is a Hopper, another one is a research vessel, another one is a deep sea vessel etc... Commented Feb 11, 2020 at 16:55
  • sorry I didn't want to confuse you Commented Feb 11, 2020 at 16:57

2 Answers 2

1

Ok, so you want to filter the displayed makers on the map regarding the option selected by the user on the dropdown.

You can change the name of type with what you want. The type if one of the dropdown values (all, research, exploration, navigation or drilling).

I have not tested the following code, but it should works!

class BoatMap extends Component {
    constructor(props) {
        super(props);
        this.state = {
            buttonEnabled: true,
            buttonClickedAt: null,
            progress: 0,
            ships: [],
            type: 'All'
        };
        this.updateRequest = this.updateRequest.bind(this);
        this.countDownInterval = null;
    }

    componentDidUpdate(prevProps, prevState) {
        if (this.state.type !== prevState.type) {
            // The user has selected a different value from the dropdown
            // To get this value: this.state.type
            // do anything you want here...
            console.log('dropdown value changed for ' + this.state.type);
        }
    }

    handleChange = e => {
        this.setState({
            type: e.target.value
        });
    };

    render() {
        return (
            <div className="google-map">
                <GoogleMapReact
                    bootstrapURLKeys={{key: 'My_KEY'}}
                    center={{
                        lat: 42.4,
                        lng: -71.1
                    }}
                    zoom={8}
                >
                    {this.state.ships.filter(ship => ship.type === this.state.type).map((ship) => (
                        <Ship ship={ship} key={ship.CALLSIGN} lat={ship.LATITUDE} lng={ship.LONGITUDE}/>
                    ))}

                    <select className="combo-companies" value={this.state.type} onChange={this.handleChange}>
                        <option value="All">All</option>
                        <option value="research">research</option>
                        <option value="exploration">exploration</option>
                        <option value="navigation">navigation</option>
                        <option value="drilling">drilling</option>
                    </select>
                </GoogleMapReact>
            </div>
        );
    }
}
Sign up to request clarification or add additional context in comments.

11 Comments

Thanks for the example. There is a little problem as I have the error TypeError: Cannot read property 'setState' of undefined in the function handleChange(event)
Ok I think is working but I can't see the updated markers as I change selection in the dropdown. Also I should say that I didn't touch type: e.target.value Is it because of that?
Just to explain: you can either add this.handleChange = this.handleChange.bind(this); on the constructor and handleChange(event) {...}, or change the method signature for a static method: handleChange = e => {,,,}
You don't have to touch type: e.target.value. You can use a console.log(e.target.value) in the handleChange method to display the value of the selected dropdown option (to verify if you get a value).
|
1
filter(ship => ship.type === this.state.type)

I have used ship.type as an example. Do you have a type property on your Ship entity?

Edit:

render() {
    // All the ships
    const ships = this.state.ships;

    // Debug
    console.log('this.state.type: ' + this.state.type);

    // Only the ships matching the dropdown selected value
    const filteredShips = ships.filter(ship => {
        console.log('ship.shipImage: ' + ship.shipImage);

        if (ship.shipImage !== this.state.type) {
            console.log('ship.shipImage does not match the filtered value');
        }

        return ship.shipImage === this.state.type;
    });

    // Debug
    console.log(ships);
    console.log(filteredShips);

    return (
        <div className="google-map">
            <GoogleMapReact
                bootstrapURLKeys={{key: 'My_KEY'}}
                center={{
                    lat: 42.4,
                    lng: -71.1
                }}
                zoom={8}
            >
                {filteredShips.map((ship) => (
                    <Ship ship={ship} key={ship.CALLSIGN} lat={ship.LATITUDE} lng={ship.LONGITUDE}/>
                ))}

                <select className="combo-companies" value={this.state.type} onChange={this.handleChange}>
                    <option value="All">All</option>
                    <option value="research">research</option>
                    <option value="exploration">exploration</option>
                    <option value="navigation">navigation</option>
                    <option value="drilling">drilling</option>
                </select>
            </GoogleMapReact>
        </div>
    );
}

8 Comments

I have const shipImage = companyImageMap[company]; on my Ship entity, that is how I associate the type with the image
So shipImage is the "type" (in my example)?
Yes, so the good news is that if I dofilter((ship) => ship.shipImage === this.state.shipImage) and update the dropdown they all disapperas....so something is happening
But I still don't understand what the problem could be to show only the selected marker...working on it
I have updated my answer. With this code you will be able to debug your code and understand why it's not working. First you have to check if the value of ship.shipImage is correct.
|

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.