ContextActionService: Unexpected error while invoking callback

You can write your topic however you want, but you need to answer these questions:

  1. What do you want to achieve? Keep it simple and clear!
    So, I’m trying to make arrow key navigation on a gui.
  2. What is the issue? Include screenshots / videos if possible!
    When I use ContextActionService, I always see this error:
    ContextActionService: Unexpected error while invoking callback: Players.SonicFrontiers011.PlayerGui.Interface.Main.Scripture.TitleScreen:220: attempt to call missing method ‘Select’ of string
  3. What solutions have you tried so far? Did you look for solutions on the Developer Hub?
    As of right now, I have not found a solution to this yet.

Here is the code:

local function NavigateArrowKeys(GuiService, slot)
	GuiService:Select(slot)
end


task.spawn(function()
	while true do
		task.wait()
		for i, slot in pairs(SaveSlotsList) do
			ContextActionService:BindAction("NavigateKeys", NavigateArrowKeys, false, Enum.KeyCode.Down)
		end
	end
end)

Help is appreciated.

3 Likes

why u put it in a while true loop?

1 Like

Cause I’m trying to constantly check if the player is pressing the down arrow key.

1 Like

you dont need to do that. A neat thing about cas is that it does just that for you.

2 Likes

Ah. Okay. I will try that out right now. Thank you.

Edit: The error still persists. It says something about:

attempt to call missing method ‘Select’ of string

ocal function NavigateArrowKeys(GuiService, slot)
	GuiService:Select(slot)
end
1 Like

Well, do you know what a “GuiService” is in the first place? Because i dont know and is there a :Select method for this service?

1 Like

Yes. There is a method called GuiService:Select(GuiObject).

More info here. GuiService:Select()

1 Like

well, :Select() isnt a thing, thats why its throwing that error.

May i know what you are trying to achieve?

Update: :Select() is in fact a thing, but you need to call it on a “selectionParent” i believe.

2 Likes

This is what I’m trying to achieve. Not sure if I’m doing something wrong.

1 Like

Why are you taking GuiService as a parameter to your bound action? The name of the action, a string, is actually getting stored there, not GuiService. You need some other way to access the things you want to access.

Parameters given by :BindAction() to the callback:

  • actionName: string
  • inputState: Enum.UserInputState
  • inputObject: InputObject

Example of bound action:

local guiService = game:GetService("GuiService")
local cas = game:GetService("ContextActionService")

local selectedObjects = --[[objects you want to use the GuiService:Select() method with]]

local function onAction(_actionName: string, _state: Enum.UserInputState, _inputObj: InputObject)
    guiService:Select(selectedObjects)
end

cas:BindAction("ActionNameHere", onAction, true, Enum.KeyCode.E)

For more information, here’s the documentation.

2 Likes

You cant call :Select() on the service it self.

1 Like

So can I have a number variable and add +1 every time the player activates the context?

1 Like

Yes. Remember, variables are just pointers to locations in memory. If the variable is assigned to in a higher scope than the bound action or is created as a global, it’ll be accessible and changed accordingly.

--for example...
local x = 0

local function foo(num: number)
    x += num
end

foo(3)
foo(5)

print(x) --> 8
1 Like

Does it make sense in a scenario like this?

What should normally be done

local x = 0

game.Players.PlayerAdded:Connect(function(Player)
x = x + 1
print(x)
end)

Errors

game.Players.PlayerAdded:Connect(function(Player)
local x = 0
x = x + 1
print(x)
end)

Putting the variable outside the function.

Yes. If you define x outside of the function, it will be incremented as expected. If you define it inside of the function, it’s not accessible by any greater scope level, e.g. the rest of the script, so attempting to use it would give you editor warning “Unknown global” and errors like “Attempt to perform arithmetic (add) on nil and number”.

1 Like

I found this from another post related:

Also, how can I check if like the player is going up or down?

I’m not sure if this would work:

local function NavigateArrowKeys(input)
	if input.UserInputType == Enum.UserInputType or Enum.UserInputType.Gamepad1 then
		if input.KeyCode == Enum.KeyCode.Up then
			-- selectButton(buttons[table.find(buttons, selected_button) + 1])
		elseif input.KeyCode == Enum.KeyCode.Down then
			--selectButton(buttons[table.find(buttons, selected_button) - 1])
		end
	end
end
1 Like

Looks like they used a table for holding their buttons, using user input to change the selection appropriately. That kind of system works, if you don’t want to manually make a table you could tag your buttons and use CollectionService:GetTagged().

It looks like it might be better to use UserInputService instead of ContextActionService, but both can be used because both provide an InputObject holding the KeyCode.

I’m pretty sure Roblox already provides a built-in navigation system for PC, using the # key to toggle it.

I guess you’re right. I’ll use UserInputService.

How can I print out what object the player currently has selected? By using GuiService.SelectedObject?

Edit: Yeah, but it prints out nil like every time.

You’d just do:

print(GuiService.SelectedObject)
--or, for the ancestry:
print(GuiService.SelectedObject:GetFullName())

Edit (in response to your edit):
Try printing it out after using the Roblox navigator (# or \ key). If it still comes out as nil, you might need to make your own custom system.

1 Like