Im trying to get sort id which is coming from my server . I can get UUID for each sort type in menu picker but how can I get their id instead of UUID when I select a sort type in Menu.As you can see in my code I can get UUID with Just(selection) but I need to get sort id which is data.id .
#State private var selection = UUID()
#Binding var sortClicked : Bool
#ObservedObject var productListViewModel = ProductListViewModel()
var sortListArray : [ProductListSortAndFilterList]
var body : some View {
HStack(alignment: .center){
Spacer()
Picker(selection: $selection, label: SortView().frame(height:UIScreen.main.bounds.height * 0.050), content: {
ForEach(sortListArray, id: \.uid, content: { item in
if item.id == "sort" {
ForEach(item.sortList ?? [],id:\.uid) { data in
Text(data.name ?? "")
.tag(data.id)
}
.onReceive(Just(selection)) { (value) in
print(value)
}
}
})
})
.pickerStyle(MenuPickerStyle())
.padding()
.background(Color(.systemBackground).edgesIgnoringSafeArea(.all))
.cornerRadius(5)
Related
I have a forEach statement that illiterates through a struct containing meal entries. If the struct is empty, I would like to display alternative Text.
My issue is when the array is empty, I receive the following error when compiling
Cannot convert value of type 'String' to expected argument type 'Meal'
let mealEntrysDinner: [String] = [
]
Section(header:Text("Dinner")){
ForEach(mealEntrysDinner, id: \.self){ meal in
if(mealEntrysDinner.isEmpty == true){
Text("Arr Empty")
}
else{
EntryRow(meal:meal)
}
}
}
Meal Structure below:
struct Meal: Identifiable, Hashable{
var id = UUID()
var mealName: String
var calories: String
var quantity: Int
var amount: String
var protein: String
}
EntryRow
struct EntryRow: View {
var meal: Meal
var body: some View {
HStack{
VStack(alignment: .leading){
Text(meal.mealName)
Text(meal.amount)
.font(.subheadline)
.foregroundColor(.gray)
}
Spacer()
Text(meal.calories)
}
}
}
There are two issues.
First, it looks like you want mealEntrysDinner to be [Meal], not [String] -- otherwise, as you've discovered, the types don't match and you can't use EntryRow.
Secondly, you have something out-of-order with your if clause -- it should be outside the ForEach:
Section(header:Text("Dinner")){
if mealEntrysDinner.isEmpty {
Text("Arr Empty")
} else {
ForEach(mealEntrysDinner) { meal in
EntryRow(meal:meal)
}
}
}
This way, the ForEach only gets displayed if mealEntrysDinner has elements.
I have a textfield that, when active, shows the filtered results from an array of "City" structs. When I type certain letters it behaves as expected, but typing other letters (consistent) crashes the app with "Fatal error: each layout item may only occur once: file SwiftUI". The city struct has an id and has the Identifiable and Hashable protocols. Here is a snippet of the code that might help troubleshoot:
struct City: Codable, Identifiable, Hashable {
let id: String
let city: String
let state: String
}
#State var cities : [City] = Bundle.main.decode("cities.json")
...
TextField(placeholder, text: $searchText) { (isEditing) in
showingDropdown = isEditing
}
...
if showingDropdown && !searchText.isEmpty {
ScrollView {
LazyVStack {
ForEach(cities.filter { $0.city.contains(searchText)}) { city in
HStack {
Text(city.city)
Text("(\(city.id))")
.foregroundColor(.lightGrayWeFly)
}
.padding(.vertical, 5)
.onTapGesture(perform: {
input = city.id
searchText = city.city
showingDropdown.toggle()
})
}
}
}
}
It's possible that I made an error when I created the JSON file but I'm having trouble narrowing things down.
using core data im storing some airport and for every airport i'm storing different note
I have created the entity Airport and the entity Briefing
Airport have 1 attribute called icaoAPT and Briefing have 4 attribute category, descript, icaoAPT, noteID
On my detailsView I show the list all the noted related to that airport, I managed to have a dynamic fetch via another view called FilterList
import SwiftUI
import CoreData
struct FilterLIst: View {
var fetchRequest: FetchRequest<Briefing>
#Environment(\.managedObjectContext) var dbContext
init(filter: String) {
fetchRequest = FetchRequest<Briefing>(entity: Briefing.entity(), sortDescriptors: [], predicate: NSPredicate(format: "airportRel.icaoAPT == %#", filter))
}
func update(_ result : FetchedResults<Briefing>) ->[[Briefing]]{
return Dictionary(grouping: result) { (sequence : Briefing) in
sequence.category
}.values.map{$0}
}
var body: some View {
List{
ForEach(update(self.fetchRequest.wrappedValue), id: \.self) { (section : Briefing) in
Section(header: Text(section.category!)) {
ForEach(section, id: \.self) { note in
Text("hello")
/// Xcode error Cannot convert value of type 'Text' to closure result type '_'
}
}
}
}
}
}
on this view I'm try to display all the section divided by category using the func update...
but Xcode give me this error , I can't understand why..Cannot convert value of type 'Text' to closure result type '_'
fore reference I list below my detailsView
import SwiftUI
struct DeatailsView: View {
#Environment(\.managedObjectContext) var dbContext
#Environment(\.presentationMode) var presentation
#State var airport : Airport
#State var note = ""
#State var noteTitle = ["SAFTY NOTE", "TAXI NOTE", "CPNOTE"]
#State var notaTitleSelected : Int = 0
#State var notaID = ""
var body: some View {
Form{
Section(header: Text("ADD NOTE Section")) {
TextField("notaID", text: self.$notaID)
.textFieldStyle(RoundedBorderTextFieldStyle())
.padding()
TextField("add Note descrip", text: self.$note)
.textFieldStyle(RoundedBorderTextFieldStyle())
.padding()
Picker(selection: $notaTitleSelected, label: Text("Class of Note")) {
ForEach(0 ..< noteTitle.count) {
Text(self.noteTitle[$0])
}
}
HStack{
Spacer()
Button(action: {
let nota = Briefing(context: self.dbContext)
nota.airportRel = self.airport
nota.icaoAPT = self.airport.icaoAPT
nota.descript = self.note
nota.category = self.noteTitle[self.notaTitleSelected]
nota.noteID = self.notaID
do {
try self.dbContext.save()
debugPrint("salvato notazione")
} catch {
print("errore nel salva")
}
}) {
Text("Salva NOTA")
}
Spacer()
}
}
Section(header: Text("View Note")) {
FilterLIst(filter: airport.icaoAPT ?? "NA")
}
}
}
}
thanks for the help
This is because you try to iterate over a single Briefing object and a ForEach loop expects a collection:
List {
ForEach(update(self.fetchRequest.wrappedValue), id: \.self) { (section: Briefing) in
Section(header: Text(section.category!)) {
ForEach(section, id: \.self) { note in // <- section is a single object
Text("hello")
/// Xcode error Cannot convert value of type 'Text' to closure result type '_'
}
}
}
}
I'd recommend you to extract the second ForEach to another method for clarity. This way you can also be sure you're passing the argument of right type ([Briefing]):
func categoryView(section: [Briefing]) -> some View {
ForEach(section, id: \.self) { briefing in
Text("hello")
}
}
Note that the result of your update method is of type [[Briefing]], which means the parameter in the ForEach is section: [Briefing] (and not Briefing):
var body: some View {
let data: [[Briefing]] = update(self.fetchRequest.wrappedValue)
return List {
ForEach(data, id: \.self) { (section: [Briefing]) in
Section(header: Text("")) { // <- can't be `section.category!`
self.categoryView(section: section)
}
}
}
}
This also means you can't write section.category! in the header as the section is an array.
You may need to access a Briefing object to get a category:
Text(section[0].category!)
(if you're sure the first element exists).
For clarity I specified types explicitly. It's also a good way to be sure you always use the right type.
let data: [[Briefing]] = update(self.fetchRequest.wrappedValue)
However, Swift can infer types automatically. In the example below, the data will be of type [[Briefing]]:
let data = update(self.fetchRequest.wrappedValue)
Hello everyone
I am creating a form that allows me to modify the data of #EnvironmentObject variable.
Therefore, I would like to be able to create a Picker that returns a String. However, after many unsuccessful attempts, I have the impression that a Picker cannot return a String.
Anyone would have an idea for a Picker that returns a String (maybe through UIKit ?).
Here's my code :
struct UserStruct {
var firstName: String
var lastName: String
var birthDate: Int
var city: String
var postalCode: Int
var street: String
var streetCode: String
var country: String
}
class User: ObservableObject {
#Published var userProfile = UserStruct()
// Other stuff here
}
// Then in my FormView:
// I declare the object as #EnvironmentObject
#EnvironmentObject var userStore: User
// I declare an array which contains all the country for the picker
let country = ["France", "Russie", "USA"]
// In my var body: some View...
// Trying to change the value of country of the userStore object
Picker(selection: $userStore.userProfile.country, label: Text("Make a choice")) {
ForEach(0 ..< country.count) { index in
Text(self.country[index]).tag(index)
}
Thank you all for your help.
you could try something like this:
let country = ["France", "Russie", "USA"]
#State var countrySelection = 0
Picker(selection: Binding(get: {
self.countrySelection
}, set: { newVal in
self.countrySelection = newVal
self.userStore.userProfile.country = self.country[self.countrySelection]
}), label: Text("Make a choice")) {
ForEach(0 ..< country.count) { index in
Text(self.country[index]).tag(index)
}
}
I'm working on my first Swift/SwiftUI project (other than the tutorials) and have run into what I think is a common problem -- the error Generic parameter 'Parent' could not be inferred -- toward the top of the view when the problem is actually with a List I'm trying to generate lower down in the form.
The app I'm building is a simple invoicing app: the user fills out the form fields and sends the invoice. An invoice can have multiple line items that the user enters one at a time and then are appended to a dictionary that should display inside the form.
This is the relevant variables from the top of the struct and the beginning of the view, where I hope I'm declaring the variables for line items correctly to modify them based on user input.
*Edited following #asperi's advice below.
#State private var lineItems = [LineItem]()
#State private var lineItem = LineItem()
struct LineItem: Codable, Hashable {
var productSku: String = ""
var productName: String = ""
var quantity: Double = 0
var unitPrice: Double = 0
}
func addLineItem(lineItem: LineItem){
lineItems.append(lineItem)
}
...
var body: some View {
NavigationView {
Form {
Section(header: Text("Customer Information")) { <-- error appears here
TextField("Customer Name", text: $customerName)
TextField("Customer Email", text: $customerEmail)
}
Here's the relevant portion of the form, where I'm trying to list all current line items and then allow the user to insert additional line items. I don't get any error until I add the List code, so I'm pretty sure I'm doing something wrong there.
Section(header: Text("Items")) {
List(lineItems, id: \.self) { item in
LineItemRow(lineItem: item)
Text(item.productName)
}
TextField("Product SKU", text: $productSKU)
TextField("Poduct Name", text: $productName)
TextField("Unit Price", text: $unitPrice, formatter: DoubleFormatter())
Picker("Quantity", selection: $quantity) {
ForEach(0 ..< 10) {
Text("\($0)")
}
}
Button(action: {
self.addLineItem(lineItem: LineItem(productSku:$productSKU,
productName:$productName,
quantity:$unitPrice,
unitPrice:$quantity))
print($lineItems)
}, label: {
Text("Add line item")
})
}
I've tested the button functionality in the console and it does seem to be appending to the dictionary correctly, but I need it to display as well.
I'm probably getting something very basic wrong with the List. Any advice?
For reference, here's the whole view:
struct AddInvoiceForm: View {
#State private var invoiceNumber: String = ""
#State private var _description: String = ""
#State private var dueDate: Date = Date()
#State private var sendImmediately: Bool = true
#State private var currency = 0
#State private var paymentType = 0
#State private var customerName: String = ""
#State private var customerEmail: String = ""
#State private var productSKU: String = ""
#State private var productName: String = ""
#State private var quantity: Int = 0
#State private var unitPrice: String = ""
#State private var lineItems = [LineItem]()
#State private var lineItem = LineItem()
struct LineItem: Codable, Hashable {
var productSku: String = ""
var productName: String = ""
var quantity: Double = 0
var unitPrice: Double = 0
}
func addLineItem(lineItem: LineItem){
lineItems.append(lineItem)
}
#State private var totalAmount: Double = 0.0
static let currencies = ["USD","GBP"]
var body: some View {
NavigationView {
Form {
Section(header: Text("Customer Information")) {
TextField("Customer Name", text: $customerName)
TextField("Customer Email", text: $customerEmail)
}
Section(header: Text("Invoice Information")) {
TextField("Invoice Number", text:$invoiceNumber)
TextField("Description", text:$_description)
DatePicker(selection: $dueDate, in: Date()..., displayedComponents: .date) {
Text("Due date")
}
Picker("Currency", selection: $currency) {
ForEach(0 ..< Self.currencies.count) {
Text(Self.currencies[$0])
}
}
}
Section(header: Text("Items")) {
List(lineItems, id: \.self) { item in
LineItemRow(lineItem: item)
Text(item.productName)
}
TextField("Product SKU", text: $productSKU)
TextField("Poduct Name", text: $productName)
TextField("Unit Price", text: $unitPrice, formatter: DoubleFormatter())
Picker("Quantity", selection: $quantity) {
ForEach(0 ..< 10) {
Text("\($0)")
}
}
Button(action: {
self.addLineItem(lineItem: LineItem(productSku:$productSKU,
productName:$productName,
quantity:$unitPrice,
unitPrice:$quantity))
print($lineItems)
}, label: {
Text("Add line item")
})
}
Section(header: Text("Totals")) {
Text("\(totalAmount)")
}
Section {
Button(action: {
print(Text("Send"))
}, label: {
Text("Send invoice")
})
}
}.navigationBarTitle("Invoice Details")
}
}
}
List(lineItems, id: \.productSku) { item in <-- I get the error when I add this
Your item is dictionary, but dictionary does not have .productSku key path, so the error.
I assume most simple & correct would be to make Item as struct
struct LineItem {
var productSku: String
...
}
...
#State private var lineItems = [LineItem]()
#State private var lineItem = LineItem()
...
List(lineItems, id: \.productSku) { item in