Roblox In-game Textbox Predictive text

Just wanted to say I added a little fix which prevents issues if the search is longer than the username.

Hope it works!

Try my solution, it should predict more than just the beginning of the name and is very flexible, allowing you to sort by which one is the best match.

@OP said his use case required only the first bit to work. Additionally, your method does not sort based on the matching, it just gives the matches with their starting indexes sorted, which isn’t what the @OP wanted.

I don’t see what you mean, it correctly sorts all the usernames by which one matches its contents first. Likely if you want to search “noob”, you are looking for something that has “noob” earlier in their username than others do. If you search between “I_am_noob”, “noob_master” and “big_noob”, it sorts with “noob_master”, “big_noob”, “I_am_noob”.

You’re missing the point here:

Is what they want. I didn’t say your sorting doesn’t work (it does, goob job), and it will for a different use case or if it was modified, but that doesn’t make your solution any better when it strays from what the @OP wants.


This discussion is derailing the topic, so if you want to continue it we should in PMs.

Here’s a really over-simplified algorithm. I used this sort of method for a small-scale call center application at my job recently. Basically you just check if the searched string contains part of the name (or vice versa). In the “Display results” loop near the bottom, you could update a UI instead of printing the names.

It determines the score simply by how much of a match was made. Perfect matches score larger. It does this simply by finding the absolute size difference between the two strings. Like I said, this is an over-simplified algorithm, but it’s very fast.

local maxResults = 4

textBox:GetPropertyChangedSignal("Text"):Connect(function()

	local results = {}
	local search = textBox.Text:lower()

	-- Score results:
	for _,player in ipairs(game.Players:GetPlayers()) do
		local name = player.Name:lower()
		if (name:find(search, 1, true) or search:find(name, 1, true)) then
			local score = math.abs(#name - #search)
			table.insert(results, {player, score})
		end
	end

	-- Sort by score:
	table.sort(results, function(a, b)
		return (a[2] < b[2])
	end)

	-- Trim results table:
	if (#results > maxResults) then
		results = {table.unpack(results, 1, maxResults)}
	end

	-- Display results:
	for i,result in ipairs(results) do
		-- Here is where you update your UI
		local player = result[1]
		print(i, player.Name)
	end

end)

In the “real world” you would want to add a cooldown debounce to type-ahead predictive searches like this. In Roblox though, with a max of 100 players in a game, there’s no problem running it on every text change right away.

Video example:

Place file from the above video:
Typeahead.rbxl (27.0 KB)

16 Likes

Is there a way to manipulate place holder to show at the same time

So for example if I put “Pl” itll display fully in the place holder in a lighter shade saying “Player”

You would need to create a text label underneath the textbox or something and change its text to copy the best match. You can also use the UserInputService/Input events to do something like fill in the full name when you press tab or the arrow keys.

This would create overlap problem where it would not match over the existing

image

Add spaces to offset the text and also put the placeholder text under the text input box. You likely want to make the input box completely transparent and have the label have the appropriate values. It is much easier if you just use chat-style alignment to the left though, as then you don’t have to worry about placeholder text size.

Spaces isnt really a reliable way.

Alignment to the left is an option but then it isnt centered which makes the UI look bad.

Question, how would i trigger an event to check whenever the user changes a value in the text??

Currently I got this:

script.Parent.Frame.TextBox:GetPropertyChangedSignal("Text"):Connect(function()
	
	script.Parent.Frame.TextBox.Text = script.Parent.Frame.TextBox.Text:upper()
	
for _,v in pairs(game.Players:GetPlayers()) do
    if string.lower(v.Name:upper()).sub(1, string.len(script.Parent.Frame.TextBox.Text)) == string.lower(script.Parent.Frame.TextBox.Text:upper()) then
        script.Parent.Frame.TextBox.TextLabel.Text = v.Name:upper()
    end
end


end)

But it wont update the “script.Parent.Frame.TextBox.TextLabel”

textBox:GetPropertyChangedSignal("Text"):Connect(func)

or

textBox.Changed:Connect(function(type)
    if type == "Text" then
        --...
    end
end)

Just updated it, check it out please.

Any solution @Wunder_Wulfe ?? Because I have no idea why it isnt firing

Any response to this??? Its been half an hour no solution found yet to my issue that came up

Maybe you are just not getting any results from the matches?

local matchedPlayer
for _, player in ipairs(Players:GetPlayers()) do
    if player.Name:lower():find(text:lower(), 1, true) == 1 then
        matchedPlayer = player
        break
    end
end
if matchedPlayer then
    thing.Text = matchedPlayer.Name
else
    thing.Text = ""
end
1 Like

No it does, it just wont change it for some reason

Have you tried using just .Changed? Also, does it say anything if you put a print statement inside of the connected function?

Pardon? where do i put this? Im confused.