xmlluaadd-onworld-of-warcraft

self in OnLoad function nil


I'm trying to create a simple addon for vanilla wow with Lua, the very first task - is to initialise some UI and to call a function for initial configuration.

MyAddonName.xml

<Ui xmlns="http://www.blizzard.com/wow/ui/"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.blizzard.com/wow/ui/ https://raw.githubusercontent.com/Gethe/wow-ui-source/live/Interface/AddOns/Blizzard_SharedXML/UI.xsd">

   <Frame name="MyAddonName" parent="UIParent">
        <Size x="384" y="512" />

        <Anchors>
            <Anchor point="CENTER" relativePoint="CENTER"
                relativeTo="UIParent" />
        </Anchors>

        <Layers>
            <Layer level="BACKGROUND">
                <Texture name="$parent_Portrait" parentKey="portrait"
                    file="Interface\Icons\INV_Misc_EngGizmos_30">
                    <Size x="60" y="60" />
                    <Anchors>
                        <Anchor point="TOPLEFT">
                            <Offset x="7" y="-6" />
                        </Anchor>
                    </Anchors>
                </Texture>
            </Layer>
        </Layers> 

        <Scripts>
           <OnLoad function="MyAddonName_OnLoad" />
        </Scripts>

  </Frame>
</Ui>

MyAddonName.lua

function Print(msg, r, g, b)
    DEFAULT_CHAT_FRAME:AddMessage("|c0033ffccMyAddonName|r "..msg.."", r, g, b)
end

function MyAddonName_OnLoad(self)
    Print("loaded"..tostring(self), 0, 1, 0) // <- self exists

    self.items = {}

end

function MyAddonName_TestFunct()
    Print(MyAddonName.items) or Print(self.items) // <- not exists, attempt to index field 'items' (a nil value)
    
end

MyAddonName_TestFunct will be called later, for test purpose I just called this from

/run MyAddonName_TestFunct()
/run MyAddonName_TestFunct()

I assumed that MyAddonName_OnLoad with self will be called after addon is loaded from xml part where self is a table that represent instance of addon, and later on some event I can call MyAddonName_TestFunct with some initial value stored in a table accessible via self.

I checked other addons (for example BetterCharacterStats) and there is a similar code, for example

BetterCharacterStats.lua

function BCS:OnLoad() // `BCS:` means that self passed implicitly

I also noticed that table BSC created explicitly, but thus I have self during check - this is not needed for me.

----

Here is a more complete example that I tested (with more code) - I'm trying to follow some tutorial, result now a bit different

And this is result of prints

Image of output

Can anyone suggest where I'm wrong?


Solution

  • The issue you're encountering with self being nil during the OnLoad event is a common problem in World of Warcraft UI scripting, especially for custom frames. This typically happens because when the OnLoad script is fired, the reference to self is not automatically passed in the way you'd expect it to be, especially when it's a custom frame or button.

    Here's why:

    In WoW, the self parameter is typically passed in automatically by the system when you use the OnLoad event in combination with a frame or button. However, if the OnLoad event is handled within XML, the frame might not have been fully initialized when the event fires, or the XML setup might not be correctly linked to the Lua function.

    The Root Cause

    The OnLoad event is generally triggered when the frame has been loaded, but in some cases (depending on the context), self might not reference the frame as expected.

    Reference the Frame Directly in Lua

    If you don’t want to change the XML, you can modify the Lua function to get a reference to the frame directly, even if self is nil. You can achieve this by referencing the frame by name within the MyAddonName_OnLoad function.

    fix:

    local frame = self or MyAddonName  -- Fallback to MyAddonName if self is nil