Trying to change textlabels inside of frame

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!
    i want to change frame visibility according to the amount of tasks there are and change these frames textlabels to the tasks, so the tasks are like Task1, Task2. they should follow this order.
  2. What is the issue? Include screenshots / videos if possible!
    When I try t make single text change, like that:
if TasksNum == 1 then
            for _,v in Frame.Frame.Tasks:GetChildren() do
                if not v:IsA("UIListLayout") then
                    if v:IsA("Frame") then
                        v.Parent.Parent.Title.Text = Tasks.ObjName.Value
                        if v.Name ~= "Task"..TasksNum then
                            v.Visible = false
                            else
                            if Tasks.Tasks.Task1.Required.Value == true then
                                v.TaskName.Text = Tasks.Tasks.Task1.TaskName.Value.." [REQUIRED]"
                                else
                                v.TaskName.Text = Tasks.Tasks.Task1.TaskName.Value
                            end
                            v.TaskRequired.Text = Tasks.Tasks.Task1.TaskDesc.Value
                        end
                    end
                end
            end

it works fine, everything works as intended.
but when i try to do multiple, like this:

elseif TasksNum >= 2 then
           for _,v in Frame.Frame.Tasks:GetChildren() do
               if not v:IsA("UIListLayout") then
                   if v:IsA("Frame") then
                       v.Parent.Parent.Title.Text = Tasks.ObjName.Value
                       if v.Task.Value > TasksNum or v.Task.Value < 1 then
                           v.Visible = false
                       end
                       for i = 1, TasksNum do
                           --if i ~= TasksNum then
                               local N = "Task"
                               local tasko = N..i
                               print(tasko)
                               local Actual = Tasks.Tasks:FindFirstChild(tasko)
                               if Actual.Required.Value == true then
                                   v.TaskName.Text = Actual.TaskName.Value.." [REQUIRED]"
                               else
                                   v.TaskName.Text = Actual.TaskName.Value
                               end
                               v.TaskRequired.Text = Actual.TaskDesc.Value
                           --end
                       end
                   end
               end
           end


herre how the values looks like:
image
image
as you see, it just clones the task title and desc of second one and does it for 3 frames. so everything else is fine but labeling is not.
3. What solutions have you tried so far? Did you look for solutions on the Developer Hub?
tried everything other way to make it. it just didn’t work oo the code was messy so it was not good for player performance.

1 Like

don’t create too many nested if statements, it consumes a lot of CPU usage

so how would i do that instead?

I am so confused of what you are trying to say. So like do you want to make labels and put the task name and desc in those labels so the players can see but your code doesn’t seem to work when you try it for multiple labels?

Yes, that’s what im trying to say. but just change labels text, not make new one.
like i have 5 frames, and it hides them, so it displays 3 tasks.

Is it possible to see your UI placements?

image
This value represents the list of the tasks, so it hides everything below 3.
and each frame has its own relative number. so 1 is 1, 2 is 2 and so on.

Why are you repeating the same thing again on the second code? Or are they both diffrent?

As long as I understand why don’t you make a for i, v in pairs(Tasks) (refering to the object value) then loop through the Tasks Frame and see if the name matches (since the task object values and the frames have the same name). If the names do match then apply the Name, description of the object value to the frames children where they belong?

Oh and it would’ve been nice if you commented on the code what they do or what are they for, something like that.

Why are you repeating the same thing again on the second code? Or are they both diffrent?

So first, I tried to make it on a single one, and it worked. When I manage to make this one work, I will remove that part. it just to reset if everything goes wrong.

As long as I understand why don’t you make a for i, v in pairs(Tasks) (refering to the object value) then loop through the Tasks Frame and see if the name matches (since the task object values and the frames have the same name) . If the names do match then apply the Name, description of the object value to the frames children where they belong?

Hmm I could try that. I will post back on how it goes.

Alrighty, it worked as inteded. tysm!
Also, any idea on how i could improove my code?

local event = game:GetService("ReplicatedStorage").Events:WaitForChild("Tasks")
local plr = game:GetService("Players").LocalPlayer
local deb  = false
local frm = plr.PlayerGui:WaitForChild("ObjNew").Frame.Tasks
event.OnClientEvent:Connect(function(TasksNum,Tasks)
	print(TasksNum,Tasks)
	if deb then return end
	deb = true
	if TasksNum ~= 0 then
		deb = true
		local Frame = plr.PlayerGui.ObjNew
		local Side = Tasks.Side.Value
		if TasksNum == 1 then
			for _,v in Frame.Frame.Tasks:GetChildren() do
				if not v:IsA("UIListLayout") then
					if v:IsA("Frame") then
						v.Parent.Parent.Title.Text = Tasks.ObjName.Value
						if v.Name ~= "Task"..TasksNum then
							v.Visible = false
							else
							if Tasks.Tasks.Task1.Required.Value == true then
								v.TaskName.Text = Tasks.Tasks.Task1.TaskName.Value.." [REQUIRED]"
								else
								v.TaskName.Text = Tasks.Tasks.Task1.TaskName.Value
							end
							v.TaskRequired.Text = Tasks.Tasks.Task1.TaskDesc.Value
						end
					end
				end
			end
			elseif TasksNum >= 2 then
			print(1)
			frm.Parent.Title.Text = Tasks.ObjName.Value
			print(frm.Parent.Title.Text)
			for _,v in pairs(Tasks.Tasks:GetChildren()) do
				print(2,v)
				print(v.Value)
				print(TasksNum)
				for _,v2 in frm:GetChildren() do
					if not v2:IsA("UIListLayout") then
						local num = v2.Task.Value
						if num > TasksNum or num < 1 then
							print(3, v)
							v2.Visible = false
							continue
						end
					end
				end
				for i = 1, TasksNum do
					print(i)
					--if i ~= TasksNum then
					local N = "Task"
					local tasko = N..i
					print(tasko)
					local Actual = Tasks.Tasks:FindFirstChild(tasko)
					print(Actual)
					local propname = frm:FindFirstChild(tasko)
					print(propname)
					if Actual.Required.Value == true then
						print(4)
						propname.TaskName.Text = Actual.TaskName.Value.." [REQUIRED]"
					else
						print(45)
						propname.TaskName.Text = Actual.TaskName.Value
					end
					print(5)
					propname.TaskRequired.Text = Actual.TaskDesc.Value
					--end
				end
			end
		end
	end
end)```

Before I try to improve it or optamize it, I am uncertain about some variables. like whats tasko or TasksNum, Side (Side Quest?). And I also don’t understand the what the code does sometimes, feels like it does something else. Also I have a question on why do you always manually do Task1.TaskName.Value When you have the for i, v in.

Also the names are just repeating inside the children which confuses on why are the children have the same name as the Parent. Try giving elements easy to know names. like if you stop doing the project and come back after a year, when u see it you may probs forgot what that element was for since there are multiple same names.

I’ll make a system where the labels will update when a/the remoteEvent is fired to update the quest Name & Description and send you the file, tell me if that’s what you are looking for.

Tasko is simply a frame name, combining i (number) and text:
“Task”…i
TasksNum is the number of tasks calculated before firing the remote.
Side is what side the frame will come out.

Also I have a question on why do you always manually do Task1.TaskName.Value When you have the for i, v in .

IDK, it was just weeks since last time I was editing it.

I’ll make a system where the labels will update when a/the remoteEvent is fired to update the quest Name & Description and send you the file, tell me if that’s what you are looking for.

No need, because I already made it work, no?

Indeed you do, And Its good as well but You are saying you are only updating the UI and I don’t get why your code looks so complicated for me to understand, maybe its because I am still learning or Its just your code looks messy, I’ll just make something that updates the UI and compare with yours while seeing If thats what you are looking for and see how you could’ve done it If it was.

Sorry again for making you wait, When I opend the previous file I checked if the errors are not working or if they are still there and seems the file wasn’t updated so I had to do some changes again and update it.

But here’s the updated code which has no comments :

local plr = game.Players.LocalPlayer

local  tasksUpdatedEvent = game:GetService("ReplicatedStorage"):WaitForChild("TasksUpdated")

local GUI = script.Parent
local tasksHolderFrame = GUI:WaitForChild("TasksFrame"):WaitForChild("TasksHolderFrame")

local debounce = false 



------------------------------------------------// Update UI once tasks are changed

tasksUpdatedEvent.OnClientEvent:Connect(function(TotalTasks, Tasks)
	
	if not TotalTasks or not Tasks then warn("Returning due to missing Argument(s)") return end
	if typeof(TotalTasks) ~= "number" then TotalTasks = 0 warn("Oops, TotalTasks is not a number. Setting to Default 0") end
	
	if debounce == true then return end
	debounce = true
	
	local side 
	---------------------------------------------------------------
	
	for _, taskFrame in pairs(tasksHolderFrame:GetChildren()) do
		if not taskFrame:IsA("Frame") or not taskFrame.Name:match("Task") then continue end
		if Tasks:FindFirstChild(taskFrame.Name) == nil then taskFrame.Visible = false continue end
		
		local foundTaskAsInstance = Tasks:FindFirstChild(taskFrame.Name)
		if tonumber(string.match(taskFrame.Name, "%d+")) > TotalTasks or TotalTasks < 1 then taskFrame.Visible = false continue end 
		
		taskFrame.TaskName.Text = ((foundTaskAsInstance.Required.Value == true) and foundTaskAsInstance.TaskName.Value.." [REQUIRED]") or foundTaskAsInstance.TaskName.Value 
		taskFrame.TaskDesc.Text = foundTaskAsInstance.TaskDesc.Value
		taskFrame:SetAttribute("Task", string.match(taskFrame.Name, "%d+"))
		
		if taskFrame.Visible ~= true then taskFrame.Visible = true end
		
		print(foundTaskAsInstance, "Task Attribute has been set to", taskFrame:GetAttribute("Task"))
		
	end
	
	---------------------------------------------------------------
	debounce = false
	
end)

Turns out I could read your code better when i transfered it to Roblox Studio. I guess I still can’t get out of my comfort zone of viewing codes in a studio.


So Here’s the Game file (66.1 KB) where I tested stuffs. This place is the updated version of my orginal place. Which contains a version of the script with explained details.

Update me if your current problem is resolved using this method or not. Hope it helps !

Oh, ok. also im trying to make a module to make multiple tasks, but im stuck on the same thing again. it just changes everything to the 2nd task.

event.OnClientEvent:Connect(function(Tasks)
	local TasksModule = require(Tasks)
	if deb then return end
	deb = true
	local ActualTask
	local function Get()
		for name, value in pairs(TasksModule) do
			if tonumber(name) and tonumber(name) == Progress then
				ActualTask = value
				return value
			else
			end
		end
	end
	local GetTask = Get()
	if Get() then
		frm.Parent.Title.Text = ActualTask.ObjName
		local Tasks = ActualTask.Tasks
		local TasksNum = 0
		for i, v in pairs(Tasks) do
			TasksNum += 1
		end
		print(TasksNum)
		for i,v in Tasks do
			for i2,v2 in frm:GetChildren() do
				if not v2:IsA("UIListLayout") then
					for i3 = 1, TasksNum do
						local N = "Task"
						local tasko = N..i3
						local propname = frm:FindFirstChild(tostring(tasko))
						print(propname,tasko)
						--print(tasko, v2.Name, i2)
						local str = string.split(v2.Name, "Task")[2]
						str = tonumber(str)
						if str > TasksNum or str < 1 then
							v2.Visible = false
							continue
							else
							if v.Required then
								propname.TaskName.Text = v.Title.." [REQUIRED]"
								else
								propname.TaskName.Text = v.Title
							end
							propname.TaskRequired.Text = v.Desc
						end
					end
				end
			end
		end
          end
     end)

and here’s the module

local plr = game:GetService("Players").LocalPlayer
local module = {
	Side = "Left"; -- Left or Right. Where the ui comes out when you talk to npc
	["1"] = {
		ObjName = "Mission No.1";
		Tasks = {
			Task1 = {
				Required = true;
				Title = "Kill 10 zombies";
				Desc = "Find zombies around the map and kill them with your gun";
				Task = "Kill"; -- Will be added later
				KillWhat = "Zombie"
			};
			Task2 = {
				Required = true;
				Title = "Find Suspicious Vent";
				Desc = "Locate a vent on a map. Pretty sus to me";
				Task = "Touch";
				TouchPart = workspace.PartsToTouch.Part;
			};
			--[[Task3 = {
				Required = true;
				Title = "???";
				Desc = "???";
				Task = "Own";
				OwnWhat = nil;
			};
			Task4 = {
				Required = true;
				Title = "";
				Desc = "";
				Task = "Kill";
				KillWhat = nil;
			};
			Task5 = {
				Required = true;
				Title = "";
				Desc = "";
				Task = "Collect";
				CollectWhat = workspace.PartsToClone.Part
			};
			Task6 = {
				Required = true;
				Title = "";
				Desc = "";
				Task = "Own";
				OwnWhat = workspace.PartsToClone.Part
			};]]
			-- ^ delete as many as u want but keep atleast one
		};
		EnableEndTask = true;
		EndTask = {
			Task = {
				Title = "Go to the Vent";
				Desc = "Locate the vent you found befoe lol";
				Task = "Touch";
				TouchPart = nil;
			};
			Type = "Cutscene" --Cutscene or Report. Cutscene is obvious and Report requires you to get back to npc.
		};
		AssignNewTask = false; -- give you another quest
		Task = nil;
		Rewards = {
			["100"] = { -- Everything Completed
			};
			["75"] = { -- if less than 100 or higher than 75
			};
			["50"] = { -- if less than 75 or higher than 50
			};
			["25"] = { -- if less than 50 or higher than 25
			};
			["0"] = { -- if less than 25 or higher than 0
			};
		}
	}
}

return module

I would still like to check your code, cuz it has unknown functions to me, like “typeof()”

For this line, You can change it to the following, I believe :

tasksUpdatedEvent.OnClientEvent:Connect(function(Tasks, TotalTasks)
	
	if not Tasks or typeof(Tasks) ~= "Instance" then warn("Returning due to missing Argument Tasks [Instance Type Needed]") return end
	if not TotalTasks or typeof(TotalTasks) ~= "number" then TotalTasks = 0 warn("Oops, Missing Argument TotalTasks or not a number type. Setting to Default 0") end

This will check if the totalTasks is a number and if it exists or Tasks is an instance or if it exists

ok, so i’ve modified my code a bit. now it looks like that:

local event = game:GetService("ReplicatedStorage").Events:WaitForChild("Tasks")
local plr = game:GetService("Players").LocalPlayer
local deb  = false
local frm = plr.PlayerGui:WaitForChild("ObjNew").Frame.Tasks
local Progress = 1
event.OnClientEvent:Connect(function(Tasks)
	
	
	local TasksModule = require(Tasks)
	local ActualTask
	
	
	local function Get()
		for name, value in pairs(TasksModule) do
			if tonumber(name) and tonumber(name) == Progress then
				ActualTask = value
				return value
			else
			end
		end
	end
	
	
	if deb then return end
	deb = true
	
	
	local side
	----------------------------------------------------------
	
	local GetTask = Get()
	
	if Get() then
		frm.Parent.Title.Text = ActualTask.ObjName
		
		
		local Tasks1 = ActualTask.Tasks
		local TasksNum = 0
		for i, v in pairs(Tasks1) do
			TasksNum += 1
		end
		
		
		if not Tasks or typeof(Tasks) ~= "Instance" then warn("Return due to missing Argument Tasks [Instance Type Needed]") return end
		if not TasksNum or typeof(TasksNum) ~= "number" then TasksNum = 0 warn("Missing Argument TasksNum or not a number type. Setting to Default. Which is 0.") end
		
		
		for i,v in Tasks1 do
			for i2,v2 in frm:GetChildren() do
				if not v2:IsA("Frame") or not v2.Name:match("Task") then continue end
				--if Tasks1..v2.Name == nil then v2.Visible = false continue end
				
				
					for i3 = 1, TasksNum do
						
						
						if tonumber(string.match(v2.Name, "%d+")) > TasksNum or TasksNum < 1 then v2.Visible = false continue end
						
						v2.TaskName.Text = ((v.Required == true) and v.Title.." [REQUIRED]") or v.Title
						v2.TaskRequired.Text = v.Desc
						v2:SetAttribute("Task",string.match(v2.Name, "%d+"))
						
						if v2.Visible ~= true then v2.Visible = true end
						
						
						print(v, "Task Attribute has been set to", v2:GetAttribute("Task"))
						

					end
					deb = false
				end
			end
	end
end)

Things that is commented i didn’t manage to fix. They output an error. But it still dublicates second task to both frames.

This. Tasks1 is a table and v2.Name is a string. so I can’t combine that.

Though it still prints both tasks, one and two. but it double as much and it does it alot.

Put local TasksModule = require(Tasks) before event.OnClientEvent:Connect(function(Tasks) since you only have to get it once or you’ll ust get it repeatly for no reason even tho the values inside the module probably doesn’t change much.


This is probably cause you have for i3 = 1, TasksNum do inside of for i2,v2 in frm:GetChildren() do or both of those are inside of for i,v in Tasks1 do. and this is probs why theres a duplication.

Did you check the game file? I explained the whole script and i also have a diffrent script as well as some tips. Maybe check it if you haven’t checked. Keep me updated


Edit : Your code feels complicated after a certain area What are you exactly trying to do. Like It seems the UI Updating has some complex requirements or maybe you have the elements in a certain place and you are strugling to work with. If you are having trouble working with the placements of elements try saving the work and working with a diffrent placement and compare the error and success

So I’ve managed to change it up a bit and it took me a while to jsut put module above the event. lol.

local event = game:GetService("ReplicatedStorage").Events:WaitForChild("Tasks")
local plr = game:GetService("Players").LocalPlayer
local deb  = false
local frm = plr.PlayerGui:WaitForChild("ObjNew").Frame.Tasks
local Progress = 1
local TasksModule = require(game:GetService("ReplicatedStorage").Modules:WaitForChild("TasksLocated"))
event.OnClientEvent:Connect(function(Tasks,NPCName)
	
	
	local ActualTask
	
	
	local function Get()
		for index,value in TasksModule do
			print(index,value)
			if index == NPCName then
				local IDKTHEName = value
				for name, value2 in pairs(IDKTHEName) do
					if tonumber(name) and tonumber(name) == Progress then
						ActualTask = value2
						return value2
					else
					end
				end
			end
		end
	end
	
	
	if deb then return end
	deb = true
	
	
	local side
	----------------------------------------------------------
	
	local GetTask = Get()
	
	if Get() then
		frm.Parent.Title.Text = ActualTask.ObjName
		
		
		local Tasks1 = ActualTask.Tasks
		local TasksNum = 0
		for i, v in pairs(Tasks1) do
			TasksNum += 1
		end
		
		
		if not Tasks or typeof(Tasks) ~= "Instance" then warn("Return due to missing Argument Tasks [Instance Type Needed]") return end
		if not TasksNum or typeof(TasksNum) ~= "number" then TasksNum = 0 warn("Missing Argument TasksNum or not a number type. Setting to Default. Which is 0.") end
		
		
		for i,v in Tasks1 do
			for i2,v2 in frm:GetChildren() do
				if not v2:IsA("Frame") or not v2.Name:match("Task") then continue end
				--if Tasks1..v2.Name == nil then v2.Visible = false continue end
				
						
						
						if tonumber(string.match(v2.Name, "%d+")) > TasksNum or TasksNum < 1 then v2.Visible = false continue end
						
						v2.TaskName.Text = ((v.Required == true) and v.Title.." [REQUIRED]") or v.Title
						v2.TaskRequired.Text = v.Desc
						v2:SetAttribute("Task",string.match(v2.Name, "%d+"))
						
						if v2.Visible ~= true then v2.Visible = true end
						
						
						print(v, "Task Attribute has been set to", v2:GetAttribute("Task"))
						
					deb = false
				end
			end
	end
end)

so here’s the code. still dublicates 2nd task to each frame. Tomorow i will make comments for you to understand if you don’t. Just really tried of debugging and trying to fix it all day

probably cause of Quote below, read it again :