0

TL;DR - I need to target and open a single menu from a bunch that are created by map()'ing an array, without a reference.

I have a problem with my React.js code that I can't quite get my head around and could do with another set of eyes, please.

The basic premise of this logic is for a user to be able to pick tasks that need carrying out in rooms of a building. The building can be from a number of sectors and as such can have a number of different rooms, each with their own tasks. In short, it needs to be dynamic.

This is simplified overview of my data structure:

  • There are a number of Sectors
    • Each Sector has multiple RoomGroups
      • Each RoomGroup has multiple Rooms
        • Each Room has multiple Tasks

When a user clicks a Property type, it has a sector associated with it. Upon selection, the RoomGroups are rendered by passing the roomGroup array in to a map().

This is a basic example of the code used for this (minus the CSS for clarity)...

const renderRoomGroups = () => {
    return (
        <div className={'requirementsInfoComponent-addRoom-row-container'}>
            {data_roomGroups.map(roomGroup => {
                return (
                    <div key={roomGroup.id}>

                        <div onClick={() => handleRoomGroupSelection(roomGroup)}>
                            {/* Icon */}
                            <MdAddCircle />

                            {/* Room name */}
                            <p>{roomGroup.group_name}</p>
                        </div>

                        {isRoomGroupMenuVisible &&
                            <div>
                                {renderRoomsMenu()}
                            </div>}

                    </div>
                )
            })}
        </div>
    )
}

const handleRoomGroupSelection = (roomGroup) => {
    setRoomGroupSelection(roomGroup);
    setIsRoomGroupMenuVisible(true);
}

const renderRoomsMenu = () => {

    const roomsByGroup = data_rooms.filter(room => room.room_group_id === roomGroupSelection.id);

    return (
        <ModalContainer>
            {roomsByGroup.map(room => {
                return (
                    <div key={room.id}>
                        <p>{room.room_name}</p>
                    </div>
                )
            })}
        </ModalContainer>
    )
}

...which produces the following UI:

Room Groups picker

The problem is, when the user clicks on a RoomGroup it should open the relevant Room's menu for them to be able to choose a room, but as the menu is within the map function it opens all the menus at the same time. I can move the menu out of the map, but then it always opens in the same place and not in the related section which is bad for UX.

So, I would like a way to only open the menu which is relevant to the selected RoomGroup, in the section it belongs to.

I've had a look around and have seen some similar questions, but these have hard coded menus that need to open dynamically which I can do, but it's not a very good option given the amount of differing data.

I've tried:

  • Having the menu code in the loop

    • No good as all the menus open on the same command
  • Having the menu code outside of the loop

    • Works well as a single menu, but will always be in the same position
  • Opening the menu around the cursor's X,Y coordinates

    • It's a bit tacky as the accuracy depends on the element's nesting and it doesn't line up properly with the UI

I thought about making each menu its own component and passing it its own onClick() function, but how would I target a single menu?

0

1 Answer 1

1

You need to show the menu only for the correct room. Try this:

 {roomGroup.id === roomGroupSelection.id &&
           <div>
               {renderRoomsMenu()}
           </div>
}

To only render the menu where you need it. And you could also remove the isRoomGroupMenuVisible

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

Comments

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.