Detect a value change in a table?

Hello,

I do not understand why the function of File:__newindex is not firing when the Name is changed in the line Players.Name = “Players”. I want this to fire when the Name is changed, like in Instances and how you can detect the change in Instance.Changed, I would like the same to happen the the Players File. The current Output is:

Objectname New file.json
Name New file.json
Type json
Folderpath 

As you can see there is no Name Players.json. How can I fix this?

local File = {}
File.__index = File

function File:__newindex(Index, Value)
	
	rawset(self, Index, Value)
	print(Index, Value)
	
	return
end

function File.new()
	local self = setmetatable({}, File)

	self.Objectname = "New file.json"

	self.Name = "New file.json"
	self.Type = "json"
	self.Folderpath = ""

	return self
end

local Players = File.new()
Players.Name = "Players"

__newindex only fires when a value is assigned to a missing key, not already existing ones

I believe you can use __index to detect new value changes?

I have just tried this using this script and it still does not work?

local File = {}
File.__index = File

function File:__index(Index)

	if Index == "Name" then
		print("Name indexed!")
	end

	return self[Index]
end

function File.new()
	local self = setmetatable({}, File)

	self.Objectname = "New file.json"

	self.Name = "New file.json"
	self.Type = "json"
	self.Folderpath = ""

	return self
end

local Players = File.new()
Players.Name = "Players"

Nevermind, __index only fires when the index is nil.
I haven’t found any alternatives beyond making the property changing a method instead of letting scripts directly edit the value or using attributes/valueobjects

e.g:

function File:setName(name)
	-- do your stuff here, or fire a bindableevent or something like that
	self.Name = name
end

There’s most likely a way to find value changes, however I don’t know any; I’d be glad if someone else could share one though.

But how do roblox’s Classes work then? Since Instance.new(“Part”) is just a metatable and Instance.new(“Part”).Name = “Part” works?

That’s not a metatable, that’s a regular table. Instance.new(“Part”).Name = “Part” works because Instance.new(“Part”) returns the part.

You’ll need to keep a separate proxy table and keep the main table empty. Because the main table is empty, __index will fire every time (have it read from the proxy table) and __newindex will fire every time (have it assign values to the proxy table)

Relevant post

1 Like
local File = {}

function File:__index(Index)
	if not File[Index] then
		return rawget(self, "File")[Index]
	end
	return File[Index]
end

function File:__newindex(Index, Value)
	if Index == "Name" or Index == "Type" then
		rawget(self, "File")[Index] = Value
		print(Index, Value)
	end
	return
end

function File.new()
	local self = setmetatable({
		File = {
			Objectname = "New file.txt",
			Name = "Newfile.txt",
			Type = "json",
			Folderpath = ""
		}
	}, File)
	return self
end