This is an expansion of an earlier thread, How to pass data from a TextField to a List (SwiftUI), but I strayed away from the topic and was advised to start a new thread.
To start, there are 2 views I need to work on; CardsView and AddView.
CardsView:
Here's the raw code:
As you can see, there is a List being used to show the Cards you have made. Obviously, we start with none. The identifiable Card is being used, along with a declaration of cardsInfo, which is calling CardsInfo, an ObservableObject class.
AddView:
Here's the raw code:
This view contains a @Binding calling on CardInfo, which is with the CardsInfo class in CardInfo.swift:
By the way, cname means Card Name.
AddView contains three TextFields and a Button. The TextFields are for the user's name, card ID, and card name respectively. The button says Create, and has no action at the moment.
The onAdd function in CardsView adds the information from the filled out cardsInfo to the List.
I need the Create button in AddView to accomplish the same thing, but still adding it to CardView's list.
To start, there are 2 views I need to work on; CardsView and AddView.
CardsView:
Here's the raw code:
Code Block // // CardsView.swift // Lunch Card (iOS) // // Created by Joshua Srery on 12/17/20. // Additional code by OOPer on Apple Developer Forums // import SwiftUI struct Card: Identifiable { let id = UUID() let title: String } struct CardsView: View { @StateObject var cardsInfo = CardsInfo() @State var showSheetView = false @State private var editMode = EditMode.inactive @State private var cards: [Card] = [] private static var count = 0 var body: some View { NavigationView { List { ForEach(cards) { cards in NavigationLink(destination: CardFullView(cname: cardsInfo.newCard.cname, name: cardsInfo.newCard.name, id: cardsInfo.newCard.id)) { CardRow(cname: cardsInfo.newCard.cname, name: cardsInfo.newCard.name, id: cardsInfo.newCard.id) } } .onDelete(perform: onDelete) .onMove(perform: onMove) } .navigationTitle("Cards") .toolbar { ToolbarItem(placement: .navigationBarLeading) { EditButton() } ToolbarItem(placement: .navigationBarTrailing) { Button(action: { self.showSheetView.toggle() }) { Image(systemName: "plus") }.sheet(isPresented: $showSheetView) { AddView(cardInfo: $cardsInfo.newCard) } } } .environment(\.editMode, $editMode) } } private var addButton: some View { switch editMode { case .inactive: return AnyView(Button(action: onAdd) { Image(systemName: "plus") }) default: return AnyView(EmptyView()) } } func onAdd() { withAnimation { cards.append(Card(title: "Card #\(Self.count)")) Self.count += 1 } } private func onDelete(offsets: IndexSet) { cards.remove(atOffsets: offsets) } private func onMove(source: IndexSet, destination: Int) { cards.move(fromOffsets: source, toOffset: destination) } }
As you can see, there is a List being used to show the Cards you have made. Obviously, we start with none. The identifiable Card is being used, along with a declaration of cardsInfo, which is calling CardsInfo, an ObservableObject class.
AddView:
Here's the raw code:
Code Block // // AddView.swift // Lunch Card (iOS) // // Created by Joshua Srery on 12/18/20. // import SwiftUI struct AddView: View { @Binding var cardInfo: CardInfo var body: some View { NavigationView { VStack { CardView(name: cardInfo.name, id: cardInfo.id) TextField("Name", text: $cardInfo.name) .textFieldStyle(RoundedBorderTextFieldStyle()) .shadow(radius: 10) TextField("ID", text: $cardInfo.id) .textFieldStyle(RoundedBorderTextFieldStyle()) .shadow(radius: 10) TextField("Card Name", text: $cardInfo.cname) .textFieldStyle(RoundedBorderTextFieldStyle()) .shadow(radius: 10) Button(action: {}) { Text("Create") .bold() } .disabled(self.cardInfo.name.isEmpty self.cardInfo.id.isEmpty self.cardInfo.cname.isEmpty) .foregroundColor(.white) .padding() .padding(.horizontal, 100) .background(Color.accentColor) .cornerRadius(10) }.padding() .navigationTitle(cardInfo.cname) .navigationBarTitleDisplayMode(.inline) } } }
This view contains a @Binding calling on CardInfo, which is with the CardsInfo class in CardInfo.swift:
Code Block // // CardsInfo.swift // Lunch Card (iOS) // // Created by Joshua Srery on 12/21/20. // Code provided by OOPer on Apple Developer Forums // import Foundation struct CardInfo { var name: String = "" var id: String = "" var cname: String = "" } class CardsInfo: ObservableObject { @Published var newCard: CardInfo = CardInfo() }
By the way, cname means Card Name.
AddView contains three TextFields and a Button. The TextFields are for the user's name, card ID, and card name respectively. The button says Create, and has no action at the moment.
The onAdd function in CardsView adds the information from the filled out cardsInfo to the List.
I need the Create button in AddView to accomplish the same thing, but still adding it to CardView's list.
One way to solve your issue is creating a sharable object and move onAdd into the object.
You can extend CardsInfo.
Something like this:
Your AddView would look like this sharing CardsInfo:
And your CardsView as:
There may be many parts to fix to make this work, but please try.
You can extend CardsInfo.
Something like this:
Code Block class CardsInfo: ObservableObject { @Published var newCard: CardInfo = CardInfo() @Published var cards: [Card] = [] //<- //↓ Move `onAdd` here (and renamed) func add() { cards.append(Card(title: "Card #\(cards.count)")) } }
Your AddView would look like this sharing CardsInfo:
Code Block struct AddView: View { @ObservedObject var cardsInfo: CardsInfo //<- Hold shared object here var body: some View { NavigationView { VStack { CardView(name: cardsInfo.newCard.name, id: cardsInfo.newCard.id) //<- TextField("Name", text: $cardsInfo.newCard.name) //<- .textFieldStyle(RoundedBorderTextFieldStyle()) .shadow(radius: 10) TextField("ID", text: $cardsInfo.newCard.id) //<- .textFieldStyle(RoundedBorderTextFieldStyle()) .shadow(radius: 10) TextField("Card Name", text: $cardsInfo.newCard.cname) //<- .textFieldStyle(RoundedBorderTextFieldStyle()) .shadow(radius: 10) Button(action: { cardsInfo.add() //<- You can call methods in a shared object }) { Text("Create") .bold() } .disabled(self.cardsInfo.newCard.name.isEmpty self.cardsInfo.newCard.id.isEmpty self.cardsInfo.newCard.cname.isEmpty) //<- .foregroundColor(.white) .padding() .padding(.horizontal, 100) .background(Color.accentColor) .cornerRadius(10) }.padding() .navigationTitle(cardsInfo.newCard.cname) //<- .navigationBarTitleDisplayMode(.inline) } } }
And your CardsView as:
Code Block struct CardsView: View { @StateObject var cardsInfo = CardsInfo() //<- Share this object @State var showSheetView = false @State private var editMode = EditMode.inactive //↓ Move `cards` into `CardsInfo` //@State private var cards: [Card] = [] //↓ You have no need to have `count` where you can easily access `cards.count` //private static var count = 0 var body: some View { NavigationView { List { ForEach(cardsInfo.cards) { card in NavigationLink(destination: CardFullView(cname: cardsInfo.newCard.cname, name: cardsInfo.newCard.name, id: cardsInfo.newCard.id)) { CardRow(cname: cardsInfo.newCard.cname, name: cardsInfo.newCard.name, id: cardsInfo.newCard.id) } } .onDelete(perform: onDelete) .onMove(perform: onMove) } .navigationTitle("Cards") .toolbar { ToolbarItem(placement: .navigationBarLeading) { EditButton() } ToolbarItem(placement: .navigationBarTrailing) { Button(action: { self.showSheetView.toggle() }) { Image(systemName: "plus") }.sheet(isPresented: $showSheetView) { AddView(cardsInfo: cardsInfo) //<- Pass the shared object } } } .environment(\.editMode, $editMode) } } //↓ Remove this method // private var addButton: some View { // switch editMode { // case .inactive: // return AnyView(Button(action: onAdd) { Image(systemName: "plus") }) // default: // return AnyView(EmptyView()) // } // } //↓ Move this into the shared object // func onAdd() { // withAnimation { // cards.append(Card(title: "Card #\(Self.count)")) // Self.count += 1 // } // } private func onDelete(offsets: IndexSet) { cardsInfo.cards.remove(atOffsets: offsets) //<- } private func onMove(source: IndexSet, destination: Int) { cardsInfo.cards.move(fromOffsets: source, toOffset: destination) //<- } }
There may be many parts to fix to make this work, but please try.