Post

Replies

Boosts

Views

Activity

how to clear a TextField when it is bound to a Swiftdata object that doesn't allow optionals
Say you have a SwiftData object that doesn't allow optionals: @Model class MySet: Identifiable { var id: UUID var weight: Int var reps: Int var isCompleted: Bool var exercise: Exercise Then you get from your MySet data a list of these MySets and append them into a State: @State var sets: [MySet] if let newSets = exercise.sets { //unwrapping the passed exercises sets if (!newSets.isEmpty) { //we passed actual sets in so set them to our set sets = newSets } And you use that State array in a ForEach and bind the Textfield directly to the data like so: ForEach($sets){ $set in TextField("\(set.weight)", value: $set.weight, formatter: NumberFormatter()) .keyboardType(.decimalPad) TextField("\(set.reps)", value: $set.reps,formatter: NumberFormatter()) .keyboardType(.decimalPad) } This will bind whatever is written into the TextField directly to the SwiftData object which is a problem because say you have 50 written and you want to change it to 60 you need to be able to clear the 50 to write the 60 and since the SwiftData object doesn't allow nil it will allow you to remove the 0 but not the 5. Is there anyway to remedy this without having the swiftData object allow optionals for example catching the clearing of the TextField and making it 0 instead of nil when its cleared?
0
0
296
Aug ’24
Cannot clear TextField when typing in a new value
I have a SwiftData object Set that has a non Optional reps and Weight and when my editView gets initialized I Set the existing sets to a State object: //The user will temporarily write to this sets array than after he is done we will save it to exercises @State var sets: [MySet] .onAppear { //this will check if the exercise has sets and if it does we will put them into State but if its doesnt we will create 2 // exercise = exercise if let newSets = exercise.sets { //unwrapping the passed exercises sets if (!newSets.isEmpty) { //we passed actual sets in so set them to our sets //Copy over all of those Sets into new Sets sets = newSets } else { //the exercise had no sets meaning an empty array was passed so we fill it with our mock Sets sets = [MySet(id: UUID(), weight: 0, reps: 0,isCompleted: false, exercise: exercise), MySet(id: UUID(), weight: 0, reps: 0, isCompleted: false, exercise: exercise)] } sortSets() } //The optional exercise sets array was empty so load default (0) sets into State else { sets = [MySet(id: UUID(), weight: 0, reps: 0,isCompleted: false, exercise: exercise), MySet(id: UUID(), weight: 0, reps: 0, isCompleted: false, exercise: exercise)] sortSets() } } Then I iterate through this State of sets and bind the weight and reps to two TextFields: ForEach($sets){ $set in //HStack for Editing the Details of a Set HStack(spacing: 10) { Group { if(set.isCompleted) { Image(systemName: "checkmark.circle.fill") .foregroundStyle(.green) // Using the custom color .font(.system(size: 22)) // Adjust the size here } else { Image(systemName: "circle") .font(.system(size: 22)) // Adjust the size here } } .onTapGesture { if(set.reps != 0 && set.weight != 0) { set.isCompleted.toggle() } } //Enter Reps and Weight HStack { VStack(alignment: .leading){ Text("Kg") .foregroundStyle(.gray) .font(.subheadline) // I am having problems with these TextFields and its when im editting an old reps or weight i cant delete the number //already there to add a new one it wont let the reps of weight TextField Become empty TextField("\(set.weight)", value: $set.weight, formatter:Formatter.valueFormatter) .keyboardType(.decimalPad) } .frame(width: 45) .padding(.leading) //.background(.yellow) //Enter Reps VStack(alignment: .leading) { Text("Reps") .foregroundStyle(.gray) .font(.subheadline) TextField("\(set.reps)", value: $set.reps,formatter:Formatter.valueFormatter) .keyboardType(.decimalPad) } .frame(width: 45) //.background(.blue) } Spacer() //Button to dublicate the current set and add it to the list //even this dupilicate button will allow me to make weight and reps 0 even thouhg its a complete copy of another set, //so why cant i make weight and reps of an existing Set 0? Button { print("Current sets count: \(sets.count)") if(sets.count <= 7) { let weight = set.weight let reps = set.reps let newSet = MySet(id: UUID(),weight: weight, reps: reps, isCompleted: false, exercise: exercise) withAnimation { sets.append(newSet) } } } label: { Image(systemName: "plus.rectangle.on.rectangle") } .buttonStyle(.borderless) } } Now the problem is that If the Set already has a Weight and Reps(i.e was added before we navigated to this view) I can't set it to 0 to change it i.e it has 5 reps I want to change it to 6 I cannot clear the 5 to write 6 it wont allow it to be cleared, strangely enough when I add a new set in the New Set button or even then I use the duplicate button to make an exact copy of the set(I can clear it zero for that duplicate one but not the original one)
3
0
264
Aug ’24
How do you skip 0 values on x axis in a SwiftUI Chart
I am plotting a SwiftUI chart from a Struct that looks like this: struct BestWeights: Identifiable { let id = UUID() let date: String let maxWeight: Int } I am then creating an array of this Struct that I will use to plot the Chart: private var bestWeights: [BestWeights] { let unformattedMonth = DateFormatter().monthSymbols[month - 1] let formattedMonth = String(unformattedMonth.prefix(3)) bestWeights.append(BestWeights(date: formattedMonth, maxWeight: bestWeightOfPeriod)) //decrementing down one month selectedDate = Calendar.current.date(byAdding: .month, value: -1, to: selectedDate) ?? selectedDate Then I am iterating through bestWeights and plotting them: Chart { ForEach(bestWeights) { bestWeight in LineMark(x: .value("Date",bestWeight.date), y: .value("MaxWeight", bestWeight.maxWeight)) .symbol { Circle() .fill(.blue) .frame(width: 7, height: 7) } } } The problem is that this produces 0 values on the Y axis that scrape the bottom of the LineMark, now I can fix this by not adding all of the bestWeights who's weight is 0 but then I don't get the full x axis I want which is 6 full months, it would show only the number of months as we have records and would jump from February to July etc.. is there any way to remove the 0 weights while keeping the X axis full of dates
1
0
357
Aug ’24