Hello,
I am attempting to make a dropdown list which will return the position of the selected value within the table it is provided. The function creates the dropdown list OK, and this was my rather abysmal attempt at returning the position of the selected option.
Now I know that at some point I need to get my local script to yield, and wait for a selection from the user.
I've hypothetically thought of a few ways of how to tackle this, perhaps the function could return a table with functions attached to each option - and then the local script would have to listen to each using multiple threads?
Regardless, I'm completely stuck and would appreciate any assistance.
Here's my module script:
function module.createDropdownList(element, options) for i, v in pairs(options) do local option = Instance.new("TextButton", element) option.Parent = element --stuff option.MouseButton1Click:connect(function() return i end) end end
And my local script:
main:WaitForChild("create").airline.MouseButton1Click:Connect(function() selection = module.createDropdownList(main.create.airline, options) print(selection) end)
This obviously, prints nil
but I thought it would be useful in giving you an idea on how I would love this to work.
Thank you for your time!
If I understand you right, you want to be able to ask
the user to pick from a set of options, and get what option they picked.
Until they pick an option, you can't do anything, so it makes sense for the ask()
call to block (wait) until an answer is back.
ie, ask
should not return
until it has its answer.
gui = script.Parent.Options function ask(...) local answer = nil for i, option in ipairs{...} do local label = Instance.new("TextButton", gui) label.Size = UDim2.new(0.5, 0, 0, 32) label.Position = UDim2.new(0, 0, 0, 32*i) label.Text = option label.MouseButton1Click:connect(function() answer = option end) end repeat wait() until answer gui:ClearAllChildren() return answer end local choice = ask("yes", "no", "maybe") print("user chose", choice)
Of course, this repeat wait()
loop is wasteful. It would be better to use a real event and :Wait()
for it. You can use a BindableEvent for that.
function ask(...) local event = Instance.new("BindableEvent") for i, option in ipairs{...} do ...... label.MouseButton1Click:connect(function() event:Fire(option) end end local answer = event.Event:Wait() gui:ClearAllChildren() return answer end
Sometimes it's an annoyance that functions block (in particular if there's multiple things going on at once).
Instead, you want the function to return immediately, but you want to say "...but when I get an answer, do this".
Promises are what you can use when a value doesn't exist yet.
A "promise" is a way of doing this. You return an event, and the caller just :Wait()
s or :Connect()
s to that event to discover the choice of the user at a later time:
function ask(...) loca event = Instance.new("BindableEvent") for i, option in ipairs{...} do ...... label.MouseButton1Click:connect(function() gui:ClearAllChildren() event:Fire(option) end end return event.Event end local onChose = ask("yes", "no", "maybe") onChose:Connect(function(choice) print("chose", choice) end) -- OR print("chose", onChose:Wait())
Callbacks aren't the best, but they're another way to do this.
It's similar to a promise, except that instead of being returned the event, you give the function to be called with the answer, and return nothing:
function ask(action, ...) for i, option in ipairs{...} do ...... label.MouseButton1Click:connect(function() gui:ClearAllChildren() action(option) end end end