Skip to content

Commit e461476

Browse files
committed
Potential reactive parent is nil fix
1 parent 464314e commit e461476

File tree

2 files changed

+40
-3
lines changed

2 files changed

+40
-3
lines changed

src/elements/Container.lua

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -689,6 +689,12 @@ end
689689
--- @private
690690
function Container:destroy()
691691
if not self:isType("BaseFrame") then
692+
for _, child in ipairs(self._values.children) do
693+
if child.destroy then
694+
child:destroy()
695+
end
696+
end
697+
self:removeAllObservers()
692698
VisualElement.destroy(self)
693699
return self
694700
else

src/plugins/reactive.lua

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,23 @@ local mathEnv = {
2020
abs = math.abs
2121
}
2222

23+
local function analyzeDependencies(expr)
24+
return {
25+
parent = expr:find("parent%."),
26+
self = expr:find("self%."),
27+
other = expr:find("[^(parent)][^(self)]%.")
28+
}
29+
end
30+
2331
local function parseExpression(expr, element, propName)
32+
local deps = analyzeDependencies(expr)
33+
34+
if deps.parent and not element.parent then
35+
errorManager.header = "Reactive evaluation error"
36+
errorManager.error("Expression uses parent but no parent available")
37+
return function() return nil end
38+
end
39+
2440
expr = expr:gsub("^{(.+)}$", "%1")
2541

2642
expr = expr:gsub("([%w_]+)%$([%w_]+)", function(obj, prop)
@@ -139,6 +155,8 @@ local observerCache = setmetatable({}, {
139155
})
140156

141157
local function setupObservers(element, expr, propertyName)
158+
local deps = analyzeDependencies(expr)
159+
142160
if observerCache[element][propertyName] then
143161
for _, observer in ipairs(observerCache[element][propertyName]) do
144162
observer.target:removeObserver(observer.property, observer.callback)
@@ -149,11 +167,11 @@ local function setupObservers(element, expr, propertyName)
149167
for ref, prop in expr:gmatch("([%w_]+)%.([%w_]+)") do
150168
if not protectedNames[ref] then
151169
local target
152-
if ref == "self" then
170+
if ref == "self" and deps.self then
153171
target = element
154-
elseif ref == "parent" then
172+
elseif ref == "parent" and deps.parent then
155173
target = element.parent
156-
else
174+
elseif deps.other then
157175
target = element:getBaseFrame():getChild(ref)
158176
end
159177

@@ -177,6 +195,11 @@ end
177195
PropertySystem.addSetterHook(function(element, propertyName, value, config)
178196
if type(value) == "string" and value:match("^{.+}$") then
179197
local expr = value:gsub("^{(.+)}$", "%1")
198+
local deps = analyzeDependencies(expr)
199+
200+
if deps.parent and not element.parent then
201+
return config.default
202+
end
180203
if not validateReferences(expr, element) then
181204
return config.default
182205
end
@@ -192,8 +215,15 @@ PropertySystem.addSetterHook(function(element, propertyName, value, config)
192215
end
193216

194217
return function(self)
218+
if element._destroyed or (deps.parent and not element.parent) then
219+
return config.default
220+
end
221+
195222
local success, result = pcall(functionCache[element][value])
196223
if not success then
224+
if result and result:match("attempt to index.-nil value") then
225+
return config.default
226+
end
197227
errorManager.header = "Reactive evaluation error"
198228
if type(result) == "string" then
199229
errorManager.error("Error evaluating expression: " .. result)
@@ -225,6 +255,7 @@ BaseElement.hooks = {
225255
end
226256
end
227257
observerCache[self] = nil
258+
functionCache[self] = nil
228259
end
229260
end
230261
}

0 commit comments

Comments
 (0)