Skip to content
This repository has been archived by the owner on Jul 17, 2024. It is now read-only.
/ typed-forms Public archive

An experimental typed form library for iOS

License

Notifications You must be signed in to change notification settings

zoul/typed-forms

Repository files navigation

Tables are often used to build forms on iOS, but the UITableView API is fairly low-level, offering a plenty of rope to hang yourself. This library attempts to think of a better, high-level API for building type-safe(r) forms using tables.

The key idea is splitting the particular form logic into a standalone view model type that handles just the logic, and then using simple, declarative rules to build the table cells from that model:

//
// The view model
//

struct Card: Equatable, CustomStringConvertible {

    let name: String
    let currencies: [String]

    var description: String {
        return name
    }
}


struct ViewModel {

    var cards: [Card]
    var selectedCard: Card {
        didSet {
            selectedCurrency = selectedCard.currencies.first!
        }
    }

    var selectedCurrency: String
    var specifyAmount: Bool
    var amount: String?

    var canBeSubmitted: Bool {
        guard specifyAmount else { return true }
        guard let amount = amount else { return false }
        return Double(amount) != nil
    }
}

//
// Sample data
//

let card1 = Card(name: "Card #1", currencies: ["CZK", "EUR"])
let card2 = Card(name: "Card #2", currencies: ["EUR", "PLN", "GBP"])
let card3 = Card(name: "Card #3", currencies: ["EUR"])
let model = ViewModel(
    cards: [card1, card2, card3], selectedCard: card2,
    selectedCurrency: "EUR", specifyAmount: false, amount: "1000")

//
// Now let’s build a form from that
//

let form = Form<ViewModel>()

form += SelectableSection("Cards", items: \.cards, selectedItem: \.selectedCard)

form += Section("Currency")
    <<< FormSegmentedCell(items: \.selectedCard.currencies, selectedItem: \.selectedCurrency)

form += Section()
    <<< FormSwitchCell(keyPath: \.specifyAmount, title: "Specify Amount")
    <<< FormTextFieldCell(keyPath: \.amount) {
        $0.textField.placeholder = "Enter amount"
        $0.textField.clearButtonMode = .whileEditing
        $0.bind(\.isHidden, to: \.specifyAmount, through: { !$0 })
    }

form += Section()
    <<< FormButtonCell(title: "Pay") {
        $0.bind(\.shouldHighlight, to: \.canBeSubmitted)
    }
}

The form object can then be used as a table view data source. The table form is always in sync with the model, there’s no need to manually update the table after model changes or vice versa.

Related Work / Inspiration

About

An experimental typed form library for iOS

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages