Debounce or disconnect MouseButton1Down:Connect

I am new to scripting and am working on a vehicle customization garage.
When player drives into garage then garage menu gui comes up.
When player purchases or installs vehicle upgrade or color, then “are you sure” confirmation gui should go away and the original category should return. So if player purchases color, then return to color menu after purchase. If player purchases engine upgrade, then return to engine menu after purchase.

The problem is that I use the same confirmation gui for both purchases and the MouseButton1Down:Connect() will not :Disconnect() or wherever I put a debounce does not work. I need some outside eyes to see what I am doing wrong. So when player installs an upgraded engine, gui works as intended until within the same menu interaction the player decides to install a color to their vehicle, when installation is “complete,” both the engine and color menu return due to the MouseButton1Down still firing from the previous clicks.

I have attempted debounces in various areas and :Disconnect() in various areas of script to no avail. The solutions on dev hub are great, but I cannot seem to apply it correctly to my script.

Here is my modulescript that handles all the stuff.

local VehicleGarageMS = {}

local ServerStorage = game:GetService("ServerStorage")
local VehicleGarageDataModule = require(ServerStorage.VehicleScripts.VehModuleScripts.VehicleGarageDataModule)

local db = false

local defaultconfirmdb = false
local engineconfirmdb = false
local colorconfirmdb = false

local engineConfirmConnection
local colorConfirmConnection

local plr

local colors = {
	["Red"] = BrickColor.new("Crimson"),
	["Blue"] = BrickColor.new("Really blue"),
	["Orange"] = BrickColor.new("Bright orange"),
	["Black"] = BrickColor.new("Really black"),
	["White"] = BrickColor.new("Institutional white"),
	["Yellow"] = BrickColor.new("Bright yellow"),
	["Green"] = BrickColor.new("Lime green"),
	["Pink"] = BrickColor.new("Pink"),
	["Purple"] = BrickColor.new("Bright violet"),
	["Grey"] = BrickColor.new("Smoky grey"),
	["Cyan"] = BrickColor.new("Cyan"),
	["Camo"] = BrickColor.new("Camo")
}

local colorPrice = 250

local enginePrices = {
	["lvl1Engine"] = 15000,
	["lvl2Engine"] = 30000,
	["lvl3Engine"] = 60000
}

local vehicleSettingsTable = {
	["Coupe"] = {
		["lvl1Engine"] = {
			["Speed"] = 70,
			["Torque"] = 4500
		},
		["lvl2Engine"] = {
			["Speed"] = 80,
			["Torque"] = 5000
		},
		["lvl3Engine"] = {
			["Speed"] = 90,
			["Torque"] = 5500
		}
	},
	["SoopCoop"] = {
		["lvl1Engine"] = {
			["Speed"] = 80,
			["Torque"] = 5500
		},
		["lvl2Engine"] = {
			["Speed"] = 90,
			["Torque"] = 6000
		},
		["lvl3Engine"] = {
			["Speed"] = 100,
			["Torque"] = 6500
		}
	},
	["MudSlinger"] = {
		["lvl1Engine"] = {
			["Speed"] = 70,
			["Torque"] = 5500
		},
		["lvl2Engine"] = {
			["Speed"] = 80,
			["Torque"] = 6000
		},
		["lvl3Engine"] = {
			["Speed"] = 90,
			["Torque"] = 6500
		}
	},
	["MadSlinger"] = {
		["lvl1Engine"] = {
			["Speed"] = 80,
			["Torque"] = 6000
		},
		["lvl2Engine"] = {
			["Speed"] = 90,
			["Torque"] = 6500
		},
		["lvl3Engine"] = {
			["Speed"] = 100,
			["Torque"] = 7000
		}
	}
}

local sortedEngineTable = {
	"lvl1Engine",
	"lvl2Engine",
	"lvl3Engine"
}

function VehicleGarageMS.DisconnectConnection(connectiontype)
	if engineConfirmConnection then
		print("engineConfirmConnection DISCONNECT")
		print(engineConfirmConnection)
		engineConfirmConnection:Disconnect()
		print(engineConfirmConnection)
	elseif colorConfirmConnection then
		
		print("colorConfirmConnection DISCONNECT")
		print(colorConfirmConnection)
		colorConfirmConnection:Disconnect()
		print(colorConfirmConnection)
	end
end


function VehicleGarageMS.setEngineConfirmFrame(ConfirmGui,EngineGui,item,vehicle,player,category)
	ConfirmGui.SureMsg.Text = "Are you sure you want to purchase "..EngineGui[item].Name.." Engine Upgrade for $"..enginePrices[item].."?"
	ConfirmGui.Visible = true
	EngineGui.Visible = false
	for i,confirmbtn in pairs(ConfirmGui:GetChildren()) do
		if confirmbtn:IsA("TextButton") then
			engineConfirmConnection = confirmbtn.MouseButton1Down:Connect(function()
				if confirmbtn.Name == "NoBtn" then
					ConfirmGui.Visible = false
					EngineGui.Visible = true
					VehicleGarageMS.DisconnectConnection(engineConfirmConnection)
				elseif confirmbtn.Name == "YesBtn" then
					if player.leaderstats.Money.Value >= enginePrices[item] then
						VehicleGarageDataModule.savePlayerData(player,category,item)
						EngineGui[item].Status.Text = "INSTALLED"
						EngineGui[item].Owned.Value = true
						EngineGui[item].Installed.Value = true
						vehicle["Vehicle Controller"].Speed.Value = vehicleSettingsTable[vehicle.Name][item]["Speed"]
						vehicle["Vehicle Controller"].Torque.Value = vehicleSettingsTable[vehicle.Name][item]["Torque"]
						player.leaderstats.Money.Value = player.leaderstats.Money.Value - 0 --enginePrices[item]
						player.PlayerGui.ScreenGui.MoneyGet.GitDatMoney.TextColor3 = Color3.new(0.666667, 0, 0)
						player.PlayerGui.ScreenGui.MoneyGet.GitDatMoney.Text = "-$0" --..enginePrices[item]
						player.PlayerGui.ScreenGui.MoneyGet.Visible = true
						wait(1.5)
						player.PlayerGui.ScreenGui.MoneyGet.Visible = false
					end
					ConfirmGui.Visible = false
					EngineGui.Visible = true
					VehicleGarageMS.DisconnectConnection(engineConfirmConnection)
				end
			end)
		end
	end
end


function VehicleGarageMS.OpenConfirmFrame(player,owned,item,category)
	local EngineGui = player.PlayerGui.VehicleGarageGui.EngineUpgradeFrame
	local colorchangegui = player.PlayerGui.VehicleGarageGui.VehicleColors.ColorsFrame
	local ConfirmGui = player.PlayerGui.VehicleGarageGui.ConfirmFrame
	local vehicle = player.Character.Humanoid.SeatPart.Parent
	if owned == false then
		if category == "EngineData" then
			local engineOrder = table.find(sortedEngineTable,item)
			if engineOrder == 1 then
				VehicleGarageMS.setEngineConfirmFrame(ConfirmGui,EngineGui,item,vehicle,player,category)
			elseif engineOrder > 1 then
				local enginePrevOrder = engineOrder - 1
				local prevEngine = sortedEngineTable[enginePrevOrder]
				if EngineGui[prevEngine].Owned.Value == true then
					VehicleGarageMS.setEngineConfirmFrame(ConfirmGui,EngineGui,item,vehicle,player,category)
				elseif EngineGui[prevEngine].Owned.Value == false then
					ConfirmGui.SureMsg.Text = "One cannot purchase "..EngineGui[item].Name.." Engine Upgrade until "..EngineGui[prevEngine].Name.." is purchased first."
					ConfirmGui.Visible = true
					ConfirmGui.NoBtn.Visible = false
					ConfirmGui.YesBtn.Visible = false
					wait(3)
					ConfirmGui.Visible = false
					ConfirmGui.NoBtn.Visible = true
					ConfirmGui.YesBtn.Visible = true
				end
			end
		elseif category == "ColorData" then
			ConfirmGui.SureMsg.Text = "Are you sure you want to purchase "..colorchangegui[item].Text.." color for $"..colorPrice.."?"
			ConfirmGui.Visible = true
			colorchangegui.Parent.Visible = false
			for i,confirmbtn in pairs(ConfirmGui:GetChildren()) do
				if confirmbtn:IsA("TextButton") then
					colorConfirmConnection = confirmbtn.MouseButton1Down:Connect(function()
						if confirmbtn.Name == "NoBtn" then
							ConfirmGui.Visible = false
							colorchangegui.Parent.Visible = true
							VehicleGarageMS.DisconnectConnection(colorConfirmConnection)
						elseif confirmbtn.Name == "YesBtn" then
							if player.leaderstats.Money.Value >= colorPrice then
								VehicleGarageDataModule.savePlayerData(player,category,item)
								colorchangegui[item].Status.Text = "INSTALLED"
								colorchangegui[item].Owned.Value = true
								colorchangegui[item].Installed.Value = true
								local vehicle = player.Character.Humanoid.SeatPart.Parent
								local color = item
								VehicleGarageMS.SetVehicleColor(vehicle,color)
								player.leaderstats.Money.Value = player.leaderstats.Money.Value - 0 --colorPrice
								player.PlayerGui.ScreenGui.MoneyGet.GitDatMoney.TextColor3 = Color3.new(0.666667, 0, 0)
								player.PlayerGui.ScreenGui.MoneyGet.GitDatMoney.Text = "-$0" --..colorPrice
								player.PlayerGui.ScreenGui.MoneyGet.Visible = true
								wait(1.5)
								player.PlayerGui.ScreenGui.MoneyGet.Visible = false
							end
							ConfirmGui.Visible = false
							colorchangegui.Parent.Visible = true
							VehicleGarageMS.DisconnectConnection(colorConfirmConnection)
						end
					end)
				end
			end
		end
	elseif owned == true then
		if category == "EngineData" then
			ConfirmGui.SureMsg.Text = "Install "..EngineGui[item].Name.." Engine Upgrade?"
			ConfirmGui.Visible = true
			EngineGui.Visible = false
			for i,confirmbtn in pairs(ConfirmGui:GetChildren()) do
				if confirmbtn:IsA("TextButton") then
					engineConfirmConnection = confirmbtn.MouseButton1Down:Connect(function()
					if confirmbtn.Name == "NoBtn" then
							ConfirmGui.Visible = false
							EngineGui.Visible = true
							VehicleGarageMS.DisconnectConnection(engineConfirmConnection)
						elseif confirmbtn.Name == "YesBtn" then
							ConfirmGui.Visible = false
							EngineGui.Visible = true
							print("EngineGui set to true")
							EngineGui[item].Status.Text = "INSTALLED"
							EngineGui[item].Installed.Value = true
							vehicle["Vehicle Controller"].Speed.Value = vehicleSettingsTable[vehicle.Name][item]["Speed"]
							vehicle["Vehicle Controller"].Torque.Value = vehicleSettingsTable[vehicle.Name][item]["Torque"]
							VehicleGarageMS.DisconnectConnection(engineConfirmConnection)
						end
					end)
				end
			end
		elseif category == "ColorData" then
			ConfirmGui.SureMsg.Text = "Are you sure you want to paint your vehicle "..colorchangegui[item].Text.." color?"
			ConfirmGui.Visible = true
			colorchangegui.Parent.Visible = false
			for i,confirmbtn in pairs(ConfirmGui:GetChildren()) do
				if confirmbtn:IsA("TextButton") then
					colorConfirmConnection = confirmbtn.MouseButton1Down:Connect(function()
						if confirmbtn.Name == "NoBtn" then
							ConfirmGui.Visible = false
							colorchangegui.Parent.Visible = true
							VehicleGarageMS.DisconnectConnection(colorConfirmConnection)
						elseif confirmbtn.Name == "YesBtn" then
							ConfirmGui.Visible = false
							colorchangegui[item].Status.Text = "INSTALLED"
							colorchangegui[item].Installed.Value = true
							local color = item
							VehicleGarageMS.SetVehicleColor(vehicle,color)
							colorchangegui.Parent.Visible = true
							print("colorchangegui set to true")
							VehicleGarageMS.DisconnectConnection(colorConfirmConnection)
						end
					end)
				end
			end
		end
	end
end

function VehicleGarageMS.CloseColorDisplay(player)
	local colorchangegui = player.PlayerGui.VehicleGarageGui.VehicleColors
	for i,colorbutton in pairs(colorchangegui.ColorsFrame:GetChildren()) do
		if (colorbutton:IsA("TextButton")) then
			colorbutton:Destroy()
		end
	end
end

function VehicleGarageMS.SetVehicleColor(vehicle,color)
	for label, colorTable in pairs(colors) do
		if label == color then
			for i,colourpart in pairs(vehicle.VehicleBody:GetChildren()) do
				if colourpart.Name == "MainBodyColor" then
					colourpart.BrickColor = colorTable
				end
			end
		end
	end
end

function VehicleGarageMS.OpenColorDisplay(player,vehicle)
	if colorconfirmdb == false then
		colorconfirmdb = true
		local colorchangegui = player.PlayerGui.VehicleGarageGui.VehicleColors
		if colorchangegui.Visible == false then
			colorchangegui.Visible = true
			for i,colorbutton in pairs(colorchangegui.ColorsFrame:GetChildren()) do
				if (colorbutton:IsA("TextButton")) then
					colorbutton.MouseButton1Down:Connect(function()
						local owned = colorbutton.Owned.Value
						local item = colorbutton.Text
						local category = "ColorData"
						VehicleGarageMS.OpenConfirmFrame(player,owned,item,category)
					end)
				end
			end
			colorchangegui.XButton.MouseButton1Down:Connect(function()
				colorchangegui.Visible = false
				colorchangegui.Parent.MenuFrame.Visible = true
				colorconfirmdb = false
			end)
		end
	end
	
end

function VehicleGarageMS.OpenEngineGui(player,vehicle)
	if engineconfirmdb == false then
		engineconfirmdb = true
		local EngineUpgradeFrame = player.PlayerGui.VehicleGarageGui.EngineUpgradeFrame
		EngineUpgradeFrame.Visible = true

		for i,button in pairs(EngineUpgradeFrame:GetChildren()) do
			button.MouseButton1Down:Connect(function()
				if button.Name ~= "XButton" then
					local owned = button.Owned.Value
					local item = button.Name
					local category = "EngineData"
					VehicleGarageMS.OpenConfirmFrame(player,owned,item,category)
				elseif button.Name == "XButton" then
					EngineUpgradeFrame.Visible = false
					EngineUpgradeFrame.Parent.MenuFrame.Visible = true
					engineconfirmdb = false
				end
			end)
		end
	end
	
end

function VehicleGarageMS.PopulateColorButtons(player)
	local colorchangegui = player.PlayerGui.VehicleGarageGui.VehicleColors
	for label, color in pairs(colors) do
		local colorbutton = Instance.new("TextButton")
		colorbutton.Parent = colorchangegui.ColorsFrame
		colorbutton.Text = label
		colorbutton.Name = label
		colorbutton.BackgroundColor3 = color.Color
		colorbutton.TextColor3 = Color3.new(1, 1, 1)
		colorbutton.TextStrokeColor3 = Color3.new(0, 0, 0)
		colorbutton.TextStrokeTransparency = 0
		local ownedValue = Instance.new("BoolValue")
		ownedValue.Name = "Owned"
		ownedValue.Parent = colorbutton
		local installedValue = Instance.new("BoolValue")
		installedValue.Name = "Installed"
		installedValue.Parent = colorbutton
		local statusLabel = Instance.new("TextLabel")
		statusLabel.Name = "Status"
		statusLabel.Position = UDim2.new(0.615, 0, 0, 0)
		statusLabel.Size = UDim2.new(0, 77, 0, 22)
		statusLabel.Text = "$"..colorPrice
		statusLabel.Parent = colorbutton
	end
end

function VehicleGarageMS.OpenGui(player)
	if db == false then
		db = true
		local humanoid = player.Character.Humanoid
		local playerUserId = "Player_"..player.UserId
		local garageGui = player.PlayerGui.VehicleGarageGui
		plr = player
		if humanoid.SeatPart then
			local seat = humanoid.SeatPart
			if seat.Name == "VehicleSeat" then
				local vehicle = seat.Parent
				local garagemenugui = player.PlayerGui.VehicleGarageGui
				local MenuFrame = garagemenugui.MenuFrame
				garagemenugui.Enabled = true
				local sessionDataHere = VehicleGarageDataModule.setupPlayerData(player)
				if sessionDataHere then
					VehicleGarageMS.PopulateColorButtons(player)
					local engineData = sessionDataHere[playerUserId]["EngineData"]
					local colorData = sessionDataHere[playerUserId]["ColorData"]
					for i,v in pairs(engineData) do
						if v == 1 then
							garageGui.EngineUpgradeFrame[i].Owned.Value = true
							garageGui.EngineUpgradeFrame[i].Status.Text = "OWNED"
						elseif v == 0 then
							garageGui.EngineUpgradeFrame[i].Status.Text = "$"..enginePrices[i]
						end
					end
				
					for i,v in pairs(colorData) do
						if v == 1 then
							garageGui.VehicleColors.ColorsFrame[i].Owned.Value = true
							garageGui.VehicleColors.ColorsFrame[i].Status.Text = "OWNED"
						end
					end
				else
					garagemenugui.Enabled = false
				end
				for i,button in pairs(MenuFrame:GetChildren()) do
					button.MouseButton1Down:Connect(function()
						if button.Name == "ColorsButton" then
							VehicleGarageMS.OpenColorDisplay(player,vehicle)
							MenuFrame.Visible = false
						elseif button.Name == "EngineButton" then
							VehicleGarageMS.OpenEngineGui(player,vehicle)
							MenuFrame.Visible = false
						elseif button.Name == "XButton" then
							VehicleGarageMS.CloseColorDisplay(player)
							garagemenugui.Enabled = false
							db = false
						end
					end)
				end
			end
		end
	end
end

return VehicleGarageMS

Here is a video explaining more clearly my issue:

I scanned through the code quickly and the general idea behind fixing the issue would be to:
In your loops that create the MouseButton1Down connections -

local connection
connection = button.MouseButton1Down:Connect(function()
--Code that does stuff based on condition here
Else
--Other code that does stuff based on another condition here

connection:Disconnect()
)

That is the general idea on where you should start. Just make sure you assign the connection to a variable that can be referenced later for :Disconnect.

You could have a global client-side variable to be a “universal debounce” for the entire GUI for that player. Then whenever you add more navigation to the GUI, you’ll check for that debounce first, and make the proper changes (true/false) after input is received.

I thought this would be the solution as well, but I have a function dedicated to disconnecting said MouseButton connections. Here:

function VehicleGarageMS.DisconnectConnection(connectiontype)
	if engineConfirmConnection then
		print("engineConfirmConnection DISCONNECT")
		print(engineConfirmConnection)
		engineConfirmConnection:Disconnect()
		print(engineConfirmConnection)
	elseif colorConfirmConnection then
		
		print("colorConfirmConnection DISCONNECT")
		print(colorConfirmConnection)
		colorConfirmConnection:Disconnect()
		print(colorConfirmConnection)
	end
end

Even if I disconnect the connections, they remain connected. I see in your example that you Disconnect twice. Is that how that works? I need to Disconnect twice?

No definitely not. That was a mistake on my part. I believe the long day gave my eyes and brain different signals.

I will scan through the code more thoroughly when I get to the computer where I can see the code more clearly than mobile.

Ok, so it turned out that calling the functions made multiple mousedown connections. So I placed them all on a table and disconnect the entire table. That seems to have done it.

local eventConnections = {}

for i,v in pairs(eventConnections) do
	v:Disconnect()
	v = nil
end

Thank you all for your assistance on this matter!

Indeed that sounds like it would be the issue. You could avoid handling it with a table by adding the disconnect in right before the connect is added.

if engineConfirmConnection then
VehicleGarageMS.DisconnectConnection(engineConfirmConnection)
end
engineConfirmConnection = confirmbtn.MouseButton1Down:Connect(function())

Or adding a debounce to ignore creation of the connection if engineConfirmConnection would also work.
Either way, glad you got it sorted!