How to stop a module script running after its been removed

I am currently requiring a module each time a create a certain UI element, as I need to pass through a value, like so

-- Quick write as example
local UI = script:WaitForChild('UI')

local UIClone = UI:Clone()
require(UIClone.UIControl)('Stuff')
UIClone.Parent = PlayerGui
-- UIControl
return function(values)

end

However, I have connections inside that return function, and when the UI gets destroyed it they continue to run. How can I find a work around for this?

1 Like

I would suggest adding an if statement which checks if the UI is still active. If it is not, it will stop running. Same with the module. If the module is deleted, it won’t continue. I hope I did understand the problem right and addressed it correctly.

Would disabling the script before removing it help?

Treat ModuleScripts as something you never delete. They are intended to be repositories of commonly used code that are used by multiple scripts, in programming languages, these are called libraries. Place them in e.g. ReplicatedStorage where they can then be required by the client as needed instead of creating/destroying them.

Additionally, when you’re dealing with connections, tie them to variables so you can call Disconnect on them later when you’re done listening to an event:

myConnection = object.Event:Connect(...)
-- later, when you clean up after yourself
myConnection:Disconnect()
2 Likes

for .Disabled = true:

script:GetPropertyChangedSignal("Disabled"):Connect(coroutine.yield)

You can’t disable module scripts

1 Like

How can I use them for UI then? I can’t use a LocalScript, as I am trying to pass a value through

require(PlayerButtons.PlayerInteractions)(InteractPlayer)

And I don’t want the UI permanently encased on the PlayerGui. I want it cloned and removed as it is needed.

Your local script could look like this.

local ReplicatedStorage = game:GetService("ReplicatedStorage")

local UI = script:WaitForChild('UI')

local UIClone = UI:Clone()
require(ReplicatedStorage.--[[path to UIControl module]])(UIClone, 'Stuff')
UIClone.Parent = PlayerGui

Your UIControl module in ReplicatedStorage could look like this.

return function(uiClone, values)
    local conn1 = someEvent:Connect(someFunct)
    local conn2 = anotherEvent:Connect(anotherFunct)
    
    local ancestryConn
    ancestryConn = uiClone.AncestryChanged:Connect(function(_, newParent)
    if not newParent then
        ancestryConn:Disconnect()
        conn1:Disconnect()
        conn2:Disconnect()
    end
end

If you create many connections, you can also store them in a table. The ancestrychanged function can also be created above the return function as long as the variables it needs and doesn’t get from the event are declared before it. If you make a separate variable for every connection, you’ll need to declare all those variables before the function declaration and update them in the function. If you use a table that contains all connections, you only need to declare it before the function.

Another version of UIControl

local allConns = {}

local function ancestryChanged(uiClone, newParent)
    if not newParent then
        for i, v in ipairs(allConns[uiClone]) do
            v:Disconnect()
        end
        allConns[uiClone] = nil
    end
end

local function createConnTable(uiClone)
    local conns = {}
    allConns[uiClone] = conns
    conns[1] = uiClone.AncestryChanged:Connect(ancestryChanged)
    return conns
end

return function(uiClone, values)
    local conns = createConnTable(uiClone)

    conns[2] = someEvent:Connect(someFunct)
    conns[3] = anotherEvent:Connect(anotherFunct)
end