How can I detect changes in nested table and get the location of the key?

Right now I have this code that detects changes in a table, however, I need to know the key’s exact location, how can I do that?

local function Proxify(currentTable: {any})
	local proxy = newproxy(true)
	local meta = getmetatable(proxy)

	meta.__index = function(self, key)
		local idx = currentTable[key]
		if idx and type(idx) == "table" then
			idx = Proxify(idx)
		end
		return idx
	end

	meta.__newindex = function(self, key, value) -- THIS KEY
		if currentTable[key] ~= value then
			currentTable[key] = value
			print("Change made in ", key, " = ", value)
		end
	end

	return proxy
end

For example if I do this:

local data = Proxify({ store = { coins = 50 } })
data.store.coins = 100

I want to get "data.store.coins" as location of the key that changed.

‘self’ is a reference to the table that you either attempted to query or you attempted to assign to.

print(self.coins) --50

Yes, but I am asking on how I can listen for changes in a table.

If I use newproxy, it will create userdata object which won’t work with table.insert.
If I don’t use newproxy, there will be still a problem since table.insert won’t trigger changes because it’s using rawset.
Comparing tables every frame would be my best option but that would be inefficient.

local Proxy = {}

local Table = setmetatable({}, {
	__index = function(Self, Key)
		return Proxy[Key]
	end,
	
	__newindex = function(Self, Key, Value)
		print("Value of table changed!")
		Proxy[Key] = Value
	end,
})

Table.Message = "Hello world!"
Table.Message = "Test!"

Notice how the print command is ran twice even though the same table key is assigned.

Yes, but now try to use table.insert, it won’t fire.

So don’t use table.insert? You have full control over your own programming.

The problem is that I want to use it.

Array[#Array + 1] = "Value"

Emulate table.insert instead, granted this is just emulating its default behavior.

1 Like
local function insert(t, v, p)
    if not p then p = #t+1 end
    for i = #t, p, -1 do
        t[i+1] = t[i]
    end
    t[p] = v
end

This should only be used if you want to shift all of the values. Otherwise use what Forummer said.

1 Like

It doesn’t work on nested tables.

function TrackTable()
	local currentRaw = {}
	
	return setmetatable({}, {
		__index = function(self, key)
			return currentRaw[key]
		end;
		
		__newindex = function(self, key, value)
			print("Changed")
			currentRaw[key] = value
		end;
	})
end

local tbl = TrackTable()

tbl.Inventory = {
	Codes = {
		"Summer2020"
	}
}

tbl.Inventory.Codes[#tbl.Inventory.Codes + 1] = "Summer2022"