How can I Bind TextField in SwiftUI while still using it to store favourites?

I have a textfield where a user can manually enter a location string. This is bound to my observed object AppState which i’ve re-labelled (app) which has a @Published var called destination. This works fine and I am able to bind the manually typed text in the text field like so:

TextField("Destination", text: $app.destination)

I have started trying to implement a favourites system where the user can save and change up to 4 destinations to quickly enter without re-typing (Only 1 is entered into the textfield at a time).

When the user presses on one of their favourites, the favourite appears in the textfield, there they can change it by typing a new one an saving it, or pressing a new favourite which replaces the one in the textField. The user must also have the option of not entering a favourite at all and be able to enter a random one too.

I have got this part working all reasonably well so far and am happy with the functionality.

My issue here is that I can’t figure out how to bind whatever is in the textfield to my ObservedObject app.destination. After some trouble shooting I have found that only the manually entered text will store in app.destination. Having a favourite appear in the textfield does not bind.

I have tried variations on .onChange() and .onTapGesture() and .focused() to run an if/else block which would simply assign the text in the textfield to app.destination but it is still buggy and you can’t then save a new favourite…

I’m going around in circles trying to figure this out and would greatly appreciate some help.

I have a minimum reproducible example for you to copy and paste. Thank you

Main View

struct ContentView: View {
    @StateObject private var favoritesViewModel = FavoritesViewModel()
    @ObservedObject var app = AppState()
    @State private var newLocation = ""
    @State private var selectedLocationIndex = 0
    @State private var userSelectedFavourite: String = ""
    @State private var favouritePressed: Bool = false
    @FocusState private var isFocused: Bool
    
    var body: some View {
        VStack {
            HStack {
                //.........THIS IS THE ISSUE TEXTFIELD
                TextField("Destination", text: (favouritePressed && !isFocused) ? $favoritesViewModel.favoriteLocations[selectedLocationIndex] : $newLocation)
                //.....................................
                .focused($isFocused)
                .contentShape(.rect)
                .textInputAutocapitalization(.characters)
                .disableAutocorrection(true)
                .padding()
                .frame(width: 280, height: 60)
                .overlay(
                    RoundedRectangle(cornerRadius: 10)
                        .stroke(Color.gray, lineWidth: 2)
                )
                
                Button("Save") {
                    saveLocation(locationIndex: selectedLocationIndex)
                }
            }
            
            Picker("Favorite Locations", selection: $selectedLocationIndex) {
                ForEach(favoritesViewModel.favoriteLocations.indices, id: .self) { index in
                    Text(favoritesViewModel.favoriteLocations[index])
                        .tag(index)
                }
            }
            .onChange(of: selectedLocationIndex) {
                favouritePressed = true
                isFocused = false
                        }
            .pickerStyle(.palette)

            Spacer()
        }
        
        .navigationTitle("Favorite Locations")
    }
    
    
    func saveLocation(locationIndex: Int) {
        print("Saving...")
        if !newLocation.isEmpty {
            favoritesViewModel.addFavoriteLocation(newLocation, locationIndex: locationIndex)
            newLocation = ""
        }
    }
}

This one just stores favourites:

class FavoritesViewModel: ObservableObject {
    // Key for UserDefaults
    let favoritesKey = "favoriteLocations"

    // UserDefaults instance
    var defaults: UserDefaults {
        UserDefaults.standard
    }

    // Published property to manage favorite locations
    @Published var favoriteLocations: [String] = []

    // Initialize with default values
    init() {
        self.favoriteLocations = loadFavorites()
    }

    // Load favorite locations from UserDefaults
    func loadFavorites() -> [String] {
        return defaults.stringArray(forKey: favoritesKey) ?? []
    }

    // Save favorite locations to UserDefaults
    func saveFavorites() {
        defaults.set(favoriteLocations, forKey: favoritesKey)
    }

    // Add a new favorite location
    func addFavoriteLocation(_ location: String, locationIndex: Int) {
        // Check if location is already in favorites and limit to 4 locations
        if !favoriteLocations.contains(location) {
            if favoriteLocations.count < 4 {
                favoriteLocations.insert(location, at: locationIndex)
            } else {
                favoriteLocations.remove(at: locationIndex)
                favoriteLocations.insert(location, at: locationIndex)
            }
            saveFavorites() // Save after adding or updating favorites
        }
    }
}

And just the Observed class:

class AppState: ObservableObject {
    
    // THIS IS THE VARIABLE IM TRYING TO SAVE TEXT TO
    @Published var destination: String = ""
    
}

Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa Dịch vụ tổ chức sự kiện 5 sao Thông tin về chúng tôi Dịch vụ sinh nhật bé trai Dịch vụ sinh nhật bé gái Sự kiện trọn gói Các tiết mục giải trí Dịch vụ bổ trợ Tiệc cưới sang trọng Dịch vụ khai trương Tư vấn tổ chức sự kiện Hình ảnh sự kiện Cập nhật tin tức Liên hệ ngay Thuê chú hề chuyên nghiệp Tiệc tất niên cho công ty Trang trí tiệc cuối năm Tiệc tất niên độc đáo Sinh nhật bé Hải Đăng Sinh nhật đáng yêu bé Khánh Vân Sinh nhật sang trọng Bích Ngân Tiệc sinh nhật bé Thanh Trang Dịch vụ ông già Noel Xiếc thú vui nhộn Biểu diễn xiếc quay đĩa Dịch vụ tổ chức tiệc uy tín Khám phá dịch vụ của chúng tôi Tiệc sinh nhật cho bé trai Trang trí tiệc cho bé gái Gói sự kiện chuyên nghiệp Chương trình giải trí hấp dẫn Dịch vụ hỗ trợ sự kiện Trang trí tiệc cưới đẹp Khởi đầu thành công với khai trương Chuyên gia tư vấn sự kiện Xem ảnh các sự kiện đẹp Tin mới về sự kiện Kết nối với đội ngũ chuyên gia Chú hề vui nhộn cho tiệc sinh nhật Ý tưởng tiệc cuối năm Tất niên độc đáo Trang trí tiệc hiện đại Tổ chức sinh nhật cho Hải Đăng Sinh nhật độc quyền Khánh Vân Phong cách tiệc Bích Ngân Trang trí tiệc bé Thanh Trang Thuê dịch vụ ông già Noel chuyên nghiệp Xem xiếc khỉ đặc sắc Xiếc quay đĩa thú vị
Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa
Thiết kế website Thiết kế website Thiết kế website Cách kháng tài khoản quảng cáo Mua bán Fanpage Facebook Dịch vụ SEO Tổ chức sinh nhật