GithubHelp home page GithubHelp logo

codecopy / objectform Goto Github PK

View Code? Open in Web Editor NEW

This project forked from haojianzong/objectform

0.0 0.0 0.0 1.44 MB

A simple yet powerful Swift library to build form for your class models.

License: Apache License 2.0

Swift 100.00%

objectform's Introduction

ObjectForm

A simple yet powerful library to build form for your class models.

Motivations

I found most form libraries for swift are too complicated to bootstrap a simple project. So I write ObjectForm to make it dead simple for building forms and binding model classes.

ObjectForm doesn't fight with you to write UIKit code. By design, it is simple to understand and extend. If you follow the example project carefully, you would find it easy to fit in your Swift project.

This project has no dependency of any other library.

Features

  • Bind class model to form rows
  • Automatic keyboards types according to model types
  • Form rows are type safe
  • Fully customizable form validation rules
  • A list of built-in UITableViewCell to support multiple types
  • Work amazingly well with your UITableView code

Requirements

  • iOS >= 13.0

Usage

  1. Copy sources
  • Copy files under /Sources into your project.
  1. Carthage (Coming soon)
  2. Swift Package Manager

Available Rows & Cells

Rows

  • StringRow: Row to support string input, full keyboard
  • DoubleRow: Row to support number input, numeric keyboard
  • DateRow: Row to bind Date value

Cells

  • TextViewInputCell: text input cell
  • SelectInputCell: support selection, provided by CollectionPicker
  • TextViewVC: A view controller with UITextView to input long text
  • ButtonCell: Show a button in the form
  • TypedInputCell: Generic cell to support type binding
  • FormInputCell: The base class for all cells

Tutorials

You can follow ObjectFormExample in ObjectFormExample to learn how to build a simple form with a class model.

Binding Model to Form

class FruitFormData: NSObject, FormDataSource {
      // Bind your custom model
      typealias BindModel = Fruit
      var basicRows: [BaseRow] = []

      func numberOfSections() -> Int {...}
      func numberOfRows(at section: Int) -> Int {...}
      func row(at indexPath: IndexPath) -> BaseRow {...}

      self.bindModel = fruit

      basicRows.append(StringRow(title: "Name",
                                 icon: "",
                                 kvcKey: "name",
                                 value: fruit.name ?? "",
                                 placeholder: nil,
                                 validator: nil))

      // Row are type safe
      basicRows.append(DoubleRow(title: "Price",
                                 icon: "",
                                 kvcKey: "price",
                                 value: fruit.price,
                                 placeholder: "",
                                 validator: nil))

      // You can build as many rows as you want
      basicRows.append(TextViewRow(title: "Note",
                                   kvcKey: "note",
                                   value: fruit.note ?? "-"))

  }
}

Showing FormDataSource in a UITableView

class FruitFormVC: UIViewController {
  private let dataSource: FruitFormData
}

extension FruitFormVC: UITableViewDataSource {
    func numberOfSections(in tableView: UITableView) -> Int {
        return dataSource.numberOfSections()
    }

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        dataSource.numberOfRows(at: section)
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

        let row = dataSource.row(at: indexPath)
        row.baseCell.setup(row)
        row.baseCell.delegate = self
        return row.baseCell
    }
}

Listening to Cell Value Change

extension FruitFormVC: FormCellDelegate {
    func cellDidChangeValue(_ cell: UITableViewCell, value: Any?) {
        let indexPath = tableView.indexPath(for: cell)!
        _ = dataSource.updateItem(at: indexPath, value: value)
    }
}

Data Validation

By providing a validation block when building a row, you can provide any validaiton rules.

basicRows.append(StringRow(title: "Name",
                           icon: "",
                           kvcKey: "name",
                           value: fruit.name ?? "",
                           placeholder: nil,
                           validator: {
                           // Custom rules for row validation
                            return !(fruit.name?.isEmpty ?? true)

}))
@objc private func saveButtonTapped() {
    guard dataSource.validateData() else {
        tableView.reloadData()
        return
    }

    navigationController?.popViewController(animated: true)
}

Row Type Safety

Since a form row use key-value-coding to update its bind model, it is important to keep the row value type the same as the object's variable type. ObjectForm enforces type safe. Every row must implement the following method:

override func isValueMatchRowType(value: Any) -> Bool

This is already implemented by built-in generic rows, for example, TypedRow<T> and SelectRow<T>.

Make Your Own Row

Making your own row and cell is easy. You have 2 options:

  1. Create concrete type using TypedRow
typealias StringRow = TypedRow<String>
  1. Subclass BaseRow
class TextViewRow: BaseRow {

    public override var baseCell: FormInputCell {
        return cell
    }

    public override var baseValue: CustomStringConvertible? {
        get { return value }
        set { value = newValue as? String }
    }

    var value: String?

    var cell: TextViewInputCell

    override func isValueMatchRowType(value: Any) -> Bool {
        let t = type(of: value)
        return String.self == t
    }

    override var description: String {
        return "<TextViewRow> \(title ?? "")"
    }

    required init(title: String, kvcKey: String, value: String?) {
        self.cell = TextViewInputCell()

        super.init()

        self.title = title
        self.kvcKey = kvcKey
        self.value = value
        self.placeholder = nil
    }
}

objectform's People

Contributors

haojianzong avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.