Skip to content

fix(es_extended/client/functions): remove every matching element in menu.removeElement - #1848

Open
seltonmt012 wants to merge 1 commit into
esx-framework:v1.14.1from
seltonmt012:fix/menu-removeelement-skip
Open

fix(es_extended/client/functions): remove every matching element in menu.removeElement#1848
seltonmt012 wants to merge 1 commit into
esx-framework:v1.14.1from
seltonmt012:fix/menu-removeelement-skip

Conversation

@seltonmt012

Copy link
Copy Markdown
Contributor

Description

menu.removeElement walks the element list forwards while calling table.remove on it. Every removal shifts the rest of the list down by one, but the loop counter still goes up, so the element that moved into the freed slot is never looked at. With several matches in a row only every second one gets removed.


Motivation

The more elements match, the more survive. Removing by type from a list where every entry matches:

elements query before after
a b c all match b left empty
a b c d e f all match b d f left empty
a b c + d (no match) 3 match b d left d
a(no) b c d(no) e 3 match a c d left a d

A single match, or matches that are already spread apart, work fine, which is why this goes unnoticed. It breaks as soon as two matching entries sit next to each other, and the caller gets no indication that anything was left behind.

Nothing in the core calls removeElement. It is part of the menu object returned by ESX.UI.Menu.Open, so this only hits resources that build menus and prune them.


Implementation Details

Iterate backwards. Indices below the current one are not affected by table.remove, so nothing gets skipped:

for i = #menu.data.elements, 1, -1 do

I pulled the function straight out of the shipped file and ran it against 12 cases: five with consecutive matches, seven that already worked (single match at the front, middle and end, no match at all, empty list, query on value, alternating matches). Unpatched it is 7/12, patched 12/12, and the seven that passed before give the same result.


Usage Example

local menu = ESX.UI.Menu.Open("default", GetCurrentResourceName(), "example", {
    title = "Example",
    elements = {
        { label = "One",   value = "a", type = "item" },
        { label = "Two",   value = "b", type = "item" },
        { label = "Three", value = "c", type = "item" },
    },
})

menu.removeElement({ type = "item" })
-- before: "Two" is still in the list
-- after:  the list is empty

PR Checklist

  • My commit messages and PR title follow the Conventional Commits standard.
  • My changes have been tested locally and function as expected.
  • My PR does not introduce any breaking changes.
  • I have provided a clear explanation of what my PR does, including the reasoning behind the changes and any relevant context.

…ement

The loop walked the element list forwards while removing from it, so every
removal shifted the next entry into the slot the counter had already passed.
With consecutive matches only every second one was removed.
@N0tNvll
N0tNvll self-requested a review August 15, 2026 00:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants