Problems with gui buttons and returning function

yo!

I recently started my first serious project and got stuck at the interface stage, I wanted to make this part optimized and modular(?) so that I could use this piece of code for everything related to selecting things, so in some mechanics the choice is single and the interface immediately closes after the selection, and in others it does not close after the selection and stuff happens (I know it sounds weird and incomprehensible, I don’t know how to explain it)

My conclusions came to this code below. But for some reason, when calling the function, it immediately returns nil, although it was planned that when clicking on a folder it will return it

I’m not really asking for a huge ready-made code solution, more how can this be implemented and what functions should be used

Thanks in advance

local function TestGuiSelection(Frame)
	Frame.ScrollingFrameFolder1.Visible = true
	Frame.ScrollingFrameFolder2.Visible = false
	Frame.ScrollingFrameFolder3.Visible = false
	
	local repbutton = Frame.ScrollingFrameFolder1.Button
	for z, Folder1 in pairs(FullFolder:GetChildren()) do
		local newbuttonFolder1 = repbutton:Clone()
		newbuttonFolder1.Name = Folder1.Name
		newbuttonFolder1.Text = Folder1.Name
		newbuttonFolder1.Parent = repbutton.Parent
		
		
		
		newbuttonFolder1.Activated:Connect(function()
			for x, Folder2 in pairs(ChooseFrame.ScrollingFrameFolder2:GetChildren()) do
				if Folder2:IsA("Frame") == true or Folder2:IsA("TextButton") == true then
					if Folder2.Visible == true then
						Folder2:Destroy()
					end
				end
			end
			
			
			Frame.ScrollingFrameFolder1.Visible = false
			Frame.ScrollingFrameFolder2.Visible = true
			Frame.ScrollingFrameFolder3.Visible = false
			
			
			local repbutton = Frame.ScrollingFrameFolder2.Button
			for x, Folder2 in pairs(Folder1:GetChildren()) do
				local newbuttonfull = repbutton:Clone()
				newbuttonFolder2.Name = Folder2.Name
				newbuttonFolder2.Text = packfull.Name
				newbuttonFolder2.Parent = repbutton.Parent
				newbuttonFolder2.Visible = true
			
			
			
				newbuttonFolder2.Activated:Connect(function()
					for c, pack in pairs(ChooseFrame.ScrollingFrameFolder3:GetChildren()) do
						if Folder3:IsA("Frame") == true or Folder3:IsA("TextButton") == true then
							if Folder3.Visible == true then
								Folder3:Destroy()
							end
						end
					end
					
				
					Frame.ScrollingFrameFolder1.Visible = false
					Frame.ScrollingFrameFolder2.Visible = false
					Frame.ScrollingFrameFolder3.Visible = true
					
					
					local repbutton = Frame.ScrollingFrameFolder3.Placeholderpack
					for c, Folder3 in pairs(Folder2:GetChildren()) do
						local newbutton = repbutton:Clone()
						local cfg = pack.CFG


						newbutton.TextLabel.Text = cfg:WaitForChild("Name").Value
						newbutton.ImageButton.Image = cfg:WaitForChild("PictureID").Value
						newbutton.Parent = repbutton.Parent
						newbutton.Visible = true
						
						
						
						newbutton.ImageButton.Activated:Connect(function()
							return Folder3
						end)
					end
				end)
			end
		end)
	end
end

Placeholder.Activated:Connect(function() --so this needs to act multiple times but i dont know how to do it lol
	if MainFrame.Visible == false then
		MainFrame.Visible = true
		local selected = nil
		selected = TestGuiSelection(SelectionFrame) --instatly prints nil for some reason without waiting for return in function
		print(selected) 
		
	else
		MainFrame.Visible = false
	end
end)

Sorry for bad english and tech-heresy

4 Likes

First of all, you need to understand why your function is returning nil. This happens because the return statement only executes when the button is clicked. If you want it to wait until a button is clicked and then return the value, you should do something like this:

local function TestGuiSelection(Frame)
	Frame.ScrollingFrameFolder1.Visible = true
	Frame.ScrollingFrameFolder2.Visible = false
	Frame.ScrollingFrameFolder3.Visible = false

	local value

	local repbutton = Frame.ScrollingFrameFolder1.Button
	for z, Folder1 in pairs(FullFolder:GetChildren()) do
		local newbuttonFolder1 = repbutton:Clone()
		newbuttonFolder1.Name = Folder1.Name
		newbuttonFolder1.Text = Folder1.Name
		newbuttonFolder1.Parent = repbutton.Parent
		
		newbuttonFolder1.Activated:Connect(function()
			for x, Folder2 in pairs(ChooseFrame.ScrollingFrameFolder2:GetChildren()) do
				if Folder2:IsA("Frame") == true or Folder2:IsA("TextButton") == true then
					if Folder2.Visible == true then
						Folder2:Destroy()
					end
				end
			end


			Frame.ScrollingFrameFolder1.Visible = false
			Frame.ScrollingFrameFolder2.Visible = true
			Frame.ScrollingFrameFolder3.Visible = false


			local repbutton = Frame.ScrollingFrameFolder2.Button
			for x, Folder2 in pairs(Folder1:GetChildren()) do
				local newbuttonfull = repbutton:Clone()
				newbuttonFolder2.Name = Folder2.Name
				newbuttonFolder2.Text = packfull.Name
				newbuttonFolder2.Parent = repbutton.Parent
				newbuttonFolder2.Visible = true



				newbuttonFolder2.Activated:Connect(function()
					for c, pack in pairs(ChooseFrame.ScrollingFrameFolder3:GetChildren()) do
						if Folder3:IsA("Frame") == true or Folder3:IsA("TextButton") == true then
							if Folder3.Visible == true then
								Folder3:Destroy()
							end
						end
					end
					
					Frame.ScrollingFrameFolder1.Visible = false
					Frame.ScrollingFrameFolder2.Visible = false
					Frame.ScrollingFrameFolder3.Visible = true
					
					local repbutton = Frame.ScrollingFrameFolder3.Placeholderpack
					for c, Folder3 in pairs(Folder2:GetChildren()) do
						local newbutton = repbutton:Clone()
						local cfg = pack.CFG
						
						newbutton.TextLabel.Text = cfg:WaitForChild("Name").Value
						newbutton.ImageButton.Image = cfg:WaitForChild("PictureID").Value
						newbutton.Parent = repbutton.Parent
						newbutton.Visible = true
						
						newbutton.ImageButton.Activated:Once(function()
							value = Folder3
						end)
					end
				end)
			end
		end)
	end
	
	repeat task.wait() until value
	
	return value
end

Placeholder.Activated:Connect(function() --so this needs to act multiple times but i dont know how to do it lol
	if MainFrame.Visible == false then
		MainFrame.Visible = true
		
		print(TestGuiSelection(SelectionFrame))
	else
		MainFrame.Visible = false
	end
end)
2 Likes

while you can use this task.wait repetition method mentioned by @inctive, you could also potentially replace this line:

with

newButton.ImageButton.Activated:Wait()
return Folder3

lmk if this works

1 Like

i think there’s more than one button (correct me if I’m wrong). The for loop would stop and return only if the first button in the for loop is clicked. It would be better if it’s done like this instead:

task.spawn(function()
newButton.ImageButton.Activated:Wait()
return Folder3
end)
1 Like

nvm, i forgot that it would still return nil, there’s no waiting lol

1 Like

i think you are correct, but do you still need that if it is already in a function? not sure

I am not sure if I understood this well
I think that you are trying to do a specific thing once a Gui is selected
rather than returning a value and running code on it, you can add a callback parameter to the function

example: unrelated to main code

-- loops through all children of scrollingFrame and calls the callback variable when they are activated
local function onParentChildrenActivated(scrollingFrame, callback)
	for _, frame :ImageButton in scrollingFrame do
		frame.Activated:Connect(function()
			-- some code
			callback(frame) -- call the callback function with frame as an argument
		end)
	end
end

--later

local scrollingFrame = ...

onParentChildrenActivated(scrollingFrame, function(frame)
	-- this function/callback would run for every child of scrollingFrame
	frame.BackgroundColor3 = Color3.new(math.random(), math.random(), math.random()) -- sets a custom color
end)

also, consider adding more comments to the script so that people can understand what it is doing

not necessary a problem but there are many indentations in the function which is making it harder for me to read it

						end) -- 1
					end --2
				end) --3
			end --4
		end) --5
	end --6
end --7

you can break the function into multiple functions or use early exit rule (idk what it is called but its something like this

--do

if not canFly then return end
--code

--instead of

if canFly then
	--code
end
1 Like

the function would still return nil. newButton.ImageButton.Activated:Wait() would only be executed if newButtonFolder2.Activated:Connect(function()) was triggered. plus, there’s the fact that there might be more than one button that could be clicked inside the for loop

ohhhh ic what you mean. also would it make sense for each function to return the value of the function nested inside it? essentially just a chain of return statements to pass on folder3.

also, for the activated function

could they all be replaced with :Wait()? but then atp just use the task.wait() repetition…
ig your solution works best, although i still havent taken a look at the other guys solution

The “early exit rule” is a design pattern known as an “early return”. It’s attributed to the never-nesting ideology, which applies strategies like inversion (inverting conditionals for early-exit opportunities) and extraction to improve code readability. For more information:

2 Likes

Thanks you alot, you really saved me. Readability of my code is the thing im still working on, althrough i cant split it into multiple functions(at least i think i cant) ill look into eary exit more deeply, thanks again

1 Like

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.