__newindex metamethod not firing

Hello,

I’m testing around with metamethods and I was attempting to create something where if I set a variable in my class it runs through the __newindex metamethod where I also run a bit of extra code.

In this case, that bit of extra code is changing TextLabel.Text = newvalue.

When I :Init() this class, it seems like the __newindex metamethod operates correctly. However, when I modify variables from a different script, __newindex doesn’t fire.

Could somebody explain the details behind this?

Class module:

local player = game.Players.LocalPlayer
local ButtonService = require(game.ReplicatedStorage.Modules.Services.ButtonService)

local module = {}
module.__newindex = function(self, key, newvalue)
	if self.Setters[key] then
		rawset(self, key, self.Setters[key](self, key, newvalue))
	end

	rawset(self, key, newvalue)
end
module.__index = module

function module:Init(frame)
	self.Setters = {
		Title = function(self, key, newvalue)
			self.PromptFrame:FindFirstChild("TitleLabel").Text = newvalue
			return newvalue
		end,
		Description = function(self, key, newvalue)
			self.PromptFrame.DescTL.Text = newvalue
			return newvalue
		end,
		Visible = function(self, key, newvalue)
			self.PromptFrame.Visible = newvalue
			return newvalue
		end,
	}
	
	self.PromptFrame = game.ReplicatedStorage.Random.StandardPromptFrame:Clone()
	self.PromptFrame.Parent = player.PlayerGui:WaitForChild("Notifications")
	
	self.Title = ""
	self.Description = "asdasdasd"
	
	self.Visible = false
	
	--print(self.PromptFrame)
	self.YesButton = {
		Enabled = false,
		Frame = self.PromptFrame:FindFirstChild("Yes"),
		callback = function()
			
		end,
	}
	self.NoButton = {
		Enabled = false,
		Frame = self.PromptFrame.No,
		callback = function()
			
		end,
	}
	self.OkButton = {
		Enabled = true,
		Frame = self.PromptFrame.Ok,
		callback = function()
			
		end,
	}
end

function module.new()
	local object = {}
	object.Setters = {}

	setmetatable(object, module)
	object:Init()
	
	return object
end

function module:PopUp()
	print"popup"
	local frame = self.PromptFrame
	frame.Position = UDim2.new(0.5,0,-0.3,0)
	
	frame:TweenPosition(UDim2.new(0.5, 0, 0.45, 0), Enum.EasingDirection.Out, Enum.EasingStyle.Sine, 0.3)
	self.Visible = true
	
	if self.YesButton.Enabled == true then
		self.YesButton.Frame.Visible = true
		ButtonService:LinkButton(self.YesButton.Frame.Top, self.YesButton.Frame.Bottom, function()
			self.YesButton.callback()
			self:Close()
		end)
	end
	if self.NoButton.Enabled == true then
		self.NoButton.Frame.Visible = true
		ButtonService:LinkButton(self.NoButton.Frame.Top, self.NoButton.Frame.Bottom, function()
			self.NoButton.callback()
			self:Close()
		end)
	end
	if self.OkButton.Enabled == true then
		self.OkButton.Frame.Visible = true
		ButtonService:LinkButton(self.OkButton.Frame.Top, self.OkButton.Frame.Bottom, function()
			self.OkButton.callback()
			self:Close()
		end)
	end
end

function module:Close()
	local frame = self.PromptFrame
	frame:TweenPosition(UDim2.new(0.5,0,-0.3,0), Enum.EasingDirection.Out, Enum.EasingStyle.Sine, 0.3, true, function()
		self.Visible = false
	end)
end

function module:Destroy()
	self.PromptFrame:Destroy()
	self = nil
end

return module

Client script:

local NoNoobsEquippedPrompt = require(game.ReplicatedStorage.Modules.Components.NotificationPrompts.StandardPrompt).new() -- __newindex metamethod operates correctly here
NoNoobsEquippedPrompt.Title = "You don't have any noobs equipped!" -- but doesn't fire here?
NoNoobsEquippedPrompt.Description = "Go home and click on a noob case to equip a noob!"

OP_SETTABLE does not invoke __newindex fallback on tables with existing indices as that executes primitive set on tables. I’d recommend that you script module.new to return a proxy instead.

2 Likes

__newindex only fires if module[index] is nil and you try to assign to it.

When you init your object it assigns to self.Title, thus _newindex will not fire.

1 Like