How do I validate dynamically added textFields on a button click in SwiftUI?
You can be done this by making a model of text fields and use one isValid flag for each InputView for the track.
Here, is the possible demo solution.
struct TextFieldModel: Identifiable {
var id = UUID()
var input: String
var correctInput: Int
var isValidate: Bool = true
}
struct InputView: View {
@Binding var input: TextFieldModel
var body: some View {
TextField("?", text: $input.input)
.foregroundColor(input.isValidate ? Color.blue : Color.red)
}
}
struct ContentViewTextFields: View {
@State var arrTextFields: [TextFieldModel] = [
.init(input: "", correctInput: 5),
.init(input: "", correctInput: 10),
.init(input: "", correctInput: 1)
]
@State var isValidate: Bool = true
var body: some View {
VStack{
ForEach(arrTextFields.indices) { index in
InputView(input: $arrTextFields[index])
.background(Color.gray.opacity(0.2))
.padding()
}
Spacer()
Button("Validate") {
// Here validate all text
arrTextFields.indices.forEach({arrTextFields[$0].isValidate = (Int(arrTextFields[$0].input) == arrTextFields[$0].correctInput) })
}
}
}
}
Create empty Text Field in View with Button Click SwiftUI
You want a dynamic number of text fields, right? Whenever you want a dynamic number of views, you want ForEach. This generates a view for each element in an array.
struct TestView: View {
@State var ingredientNames = [""] /// array of ingredients
var body: some View {
VStack { /// vertical stack of ingredients
ForEach(ingredientNames.indices, id: \.self) { index in
TextField("Example Field", text: $ingredientNames[index]) /// use each element in the array
}
Button(action: {
/// Add another empty text field to the view
ingredientNames.append("")
}) {
Image(systemName: "plus.circle")
.foregroundColor(Color.black)
}
}
}
}
Result:
How can I update a TextField value and have its associated index in an array update as well?
I ended up solving the issue by converting @State var item: RecipeStepModel
in my view model to @Binding var item: RecipeStepModel
struct CustomTextField : View {
@Binding var item : RecipeStepModel
var body : some View {
Text(String(item.stepNumber) + ".")
TextField("", text: $item.stepName)
}
Once this change was made, I had to alter the code in my ForEach to pass a binding to the CustomTextField view model. Additionally, I had to change ForEach(recipeArray, id: \.id)
to ForEach(recipeArray.indices, id: \.self)
:
List {
ForEach(recipeArray.indices, id: \.self) { index in
HStack {
CustomTextField(item: $recipeArray[index]) //<--change made here
}
}.onDelete { (indexSet) in
recipeArray.remove(atOffsets: indexSet)
}
I am now able to both successfully delete items from the list, and update items in the array simply by changing the value in the appropriate TextField
Create an arbitrary number of state variables in SwiftUI
Using the strategy in the edit that you added, with the Dictionary, you could provide a custom Binding, like this:
func bindingForID(id: String) -> Binding<String> {
.init {
answers[id] ?? ""
} set: { newValue in
answers[id] = newValue
}
}
And you could use it like this:
TextField(surveyQuestion.placeholder, text: bindingForID(id: surveyQuestion.id))
In terms of adding this data to Firestore, you could trigger Firestore updates in the set
closure from the custom binding. However, I'd probably recommend moving this logic to a @Published
property on a view model (ObservableObject
) where you could use Combine to do things like Debouncing before you send the data to Firestore (probably a little beyond the scope of this question).
Swift - validating UITextField
Alternatively, you can use this, which is called every time a key is pressed:
name1.addTarget(self, action: "textFieldDidChange:", forControlEvents: UIControlEvents.EditingChanged)
name2.addTarget(self, action: "textFieldDidChange:", forControlEvents: UIControlEvents.EditingChanged)
name3.addTarget(self, action: "textFieldDidChange:", forControlEvents: UIControlEvents.EditingChanged)
name4.addTarget(self, action: "textFieldDidChange:", forControlEvents: UIControlEvents.EditingChanged)
func textFieldDidChange(textField: UITextField) {
if name1.text?.isEmpty || name2.text?.isEmpty || name3.text?.isEmpty || name4.text?.isEmpty {
//Disable button
} else {
//Enable button
}
}
Dynamically add cells to SwiftUI LazyGrid
You should use dynamic variant of ForEach
in this case, like
var body: some View {
LazyVGrid(columns: gridLayout) {
ForEach(counter.indices, id: \.self) { item in // << here !!
textFieldDidBeginEditing and textFieldDidEndEditing in SwiftUI
TextField
has onEditingChanged
and onCommit
callbacks.
For example:
@State var text = ""
@State var text2 = "default"
var body: some View {
VStack {
TextField($text, placeholder: nil, onEditingChanged: { (changed) in
self.text2 = "Editing Changed"
}) {
self.text2 = "Editing Commited"
}
Text(text2)
}
}
The code in onEditingChanged
is only called when the user selects the textField
, and onCommit
is only called when return, done, etc. is tapped.
Edit: When the user changes from one TextField
to another, the previously selected TextField
's onEditingChanged
is called once, with changed
(the parameter) equaling false
, and the just-selected TextField
's onEditingChanged
is also called, but with the parameter equaling true
. The onCommit
callback is not called for the previously selected TextField
.
Edit 2:
Adding an example for if you want to call a function committed()
when a user taps return or changes TextField
, and changed()
when the user taps the TextField
:
@State var text = ""
var body: some View {
VStack {
TextField($text, placeholder: nil, onEditingChanged: { (changed) in
if changed {
self.changed()
} else {
self.committed()
}
}) {
self.committed()
}
}
}
How to check if a text field is empty or not in swift
Simply comparing the textfield object to the empty string ""
is not the right way to go about this. You have to compare the textfield's text
property, as it is a compatible type and holds the information you are looking for.
@IBAction func Button(sender: AnyObject) {
if textField1.text == "" || textField2.text == "" {
// either textfield 1 or 2's text is empty
}
}
Swift 2.0:
Guard:
guard let text = descriptionLabel.text where !text.isEmpty else {
return
}
text.characters.count //do something if it's not empty
if:
if let text = descriptionLabel.text where !text.isEmpty
{
//do something if it's not empty
text.characters.count
}
Swift 3.0:
Guard:
guard let text = descriptionLabel.text, !text.isEmpty else {
return
}
text.characters.count //do something if it's not empty
if:
if let text = descriptionLabel.text, !text.isEmpty
{
//do something if it's not empty
text.characters.count
}
How do I check when a UITextField changes?
SWIFT
Swift 4.2
textfield.addTarget(self, action: #selector(ViewController.textFieldDidChange(_:)), for: .editingChanged)
and
@objc func textFieldDidChange(_ textField: UITextField) {
}
SWIFT 3 & swift 4.1
textField.addTarget(self, action: #selector(ViewController.textFieldDidChange(_:)), for: .editingChanged)
and
func textFieldDidChange(_ textField: UITextField) {
}
SWIFT 2.2
textField.addTarget(self, action: #selector(ViewController.textFieldDidChange(_:)), forControlEvents: UIControlEvents.EditingChanged)
and
func textFieldDidChange(textField: UITextField) {
//your code
}
OBJECTIVE-C
[textField addTarget:self action:@selector(textFieldDidChange:) forControlEvents:UIControlEventEditingChanged];
and textFieldDidChange method is
-(void)textFieldDidChange :(UITextField *) textField{
//your code
}
Related Topics
Swift - Avaudioplayer, Sound Doesn't Play Correctly
Converting a C-Style for Loop That Uses Division for the Step to Swift 3
How to Rewrite Swift ++ Operator in : Ternary Operator
How to Validate Dynamically Added Textfields on a Button Click in Swiftui
Lazy Loading Properties in Swift
How to Add an Optional String Extension
In Swift, How to Have a Uiscrollview Subclass That Has an Internal and External Delegate
Pointers, Pointer Arithmetic, and Raw Data in Swift
Get Current Time as String Swift 3.0
Converting Swift Array to Cfarray in Xcode 8 (Swift 3)
Extending Collection with a Recursive Property/Method That Depends on the Element Type
Retrieve String Value from Function with Closure in Swift
Format Realtime Stopwatch Timer to the Hundredth Using Swift
Fibonacci Calculator Stack Overflows at 93Nd Number in Swift
Consume Swift Package for Multiple Targets and Platforms in a Project
How to Declare an Inline Function in Swift